remotes::install_github("braverock/factorAnalytics",  build_vignettes = TRUE, force = TRUE)
Downloading GitHub repo braverock/factorAnalytics@HEAD
These packages have more recent versions available.
It is recommended to update all of them.
Which would you like to update?

1: All                               
2: CRAN packages only                
3: None                              
4: R6       (2.4.1  -> 2.5.0 ) [CRAN]
5: testthat (2.3.2  -> 3.0.0 ) [CRAN]
6: digest   (0.6.26 -> 0.6.27) [CRAN]
7: xfun     (0.18   -> 0.19  ) [CRAN]
8: quantreg (5.74   -> 5.75  ) [CRAN]

  
  
  
✓  checking for file ‘/tmp/RtmpNUhB5u/remotes2a1c605fdfccd7/braverock-FactorAnalytics-e378067/DESCRIPTION’ (366ms)

  
─  preparing ‘FactorAnalytics’:
   checking DESCRIPTION meta-information ...
  
✓  checking DESCRIPTION meta-information

  
─  checking for LF line-endings in source and make files and shell scripts
─  checking for empty or unneeded directories

  
─  looking to see if a ‘data/datalist’ file should be added

  
     NB: this package now depends on R (>= 3.5.0)
     WARNING: Added dependency on R >= 3.5.0 because serialized objects in  serialize/load version 3 cannot be read in older versions of R.  File(s) containing such objects: ‘FactorAnalytics/data/brkAnnual.rda’  WARNING: Added dependency on R >= 3.5.0 because serialized objects in  serialize/load version 3 cannot be read in older versions of R.  File(s) containing such objects:  ‘FactorAnalytics/data/brkMonthlyBloomberg.rda’  WARNING: Added dependency on R >= 3.5.0 because serialized objects in  serialize/load version 3 cannot be read in older versions of R.  File(s) containing such objects:  ‘FactorAnalytics/data/scoresSPGMI.rda’  WARNING: Added dependency on R >= 3.5.0 because serialized objects in  serialize/load version 3 cannot be read in older versions of R.  File(s) containing such objects:  ‘FactorAnalytics/data/scoresSPGMIraw.rda’  WARNING: Added dependency on R >= 3.5.0 because serialized objects in  serialize/load version 3 cannot be read in older versions of R.  File(s) containing such objects: ‘FactorAnalytics/data/spxAnnual.rda’  WARNING: Added dependency on R >= 3.5.0 because serialized objects in  serialize/load version 3 cannot be read in older versions of R.  File(s) containing such objects:  ‘FactorAnalytics/data/stocksCRSP.rda’  WARNING: Added dependency on R >= 3.5.0 because serialized objects in  serialize/load version 3 cannot be read in older versions of R.  File(s) containing such objects:  ‘FactorAnalytics/data/stocksCRSPscoresSPGMI.rda’  WARNING: Added dependency on R >= 3.5.0 because serialized objects in  serialize/load version 3 cannot be read in older versions of R.  File(s) containing such objects:  ‘FactorAnalytics/data/stocksCRSPscoresSPGMIraw.rda’
─  building ‘FactorAnalytics_2.0.40.tar.gz’

  
   
Installing package into ‘/home/smacanovic/R/x86_64-pc-linux-gnu-library/4.0’
(as ‘lib’ is unspecified)
* installing *source* package ‘FactorAnalytics’ ...
** using staged installation
** R
** data
** inst
** byte-compile and prepare package for lazy loading
rlm is already registered in the fit.models registry
covfm is already registered in the fit.models registry
Warning: replacing previous import ‘data.table::last’ by ‘xts::last’ when loading ‘FactorAnalytics’
Warning: replacing previous import ‘data.table::first’ by ‘xts::first’ when loading ‘FactorAnalytics’
Warning: replacing previous import ‘data.table::melt’ by ‘reshape2::melt’ when loading ‘FactorAnalytics’
Note: possible error in 'standardizeExposures(obj = rollingObject, ': unused argument (obj = rollingObject) 
Note: possible error in 'extractRegressionStats(obj = rollingObject, ': unused argument (obj = rollingObject) 
** help
*** installing help indices
** building package indices
** installing vignettes
** testing if installed package can be loaded from temporary location
rlm is already registered in the fit.models registry
covfm is already registered in the fit.models registry
Warning: replacing previous import ‘data.table::last’ by ‘xts::last’ when loading ‘FactorAnalytics’
Warning: replacing previous import ‘data.table::first’ by ‘xts::first’ when loading ‘FactorAnalytics’
Warning: replacing previous import ‘data.table::melt’ by ‘reshape2::melt’ when loading ‘FactorAnalytics’
** testing if installed package can be loaded from final location
rlm is already registered in the fit.models registry
covfm is already registered in the fit.models registry
Warning: replacing previous import ‘data.table::last’ by ‘xts::last’ when loading ‘FactorAnalytics’
Warning: replacing previous import ‘data.table::first’ by ‘xts::first’ when loading ‘FactorAnalytics’
Warning: replacing previous import ‘data.table::melt’ by ‘reshape2::melt’ when loading ‘FactorAnalytics’
** testing if installed package keeps a record of temporary installation path
* DONE (FactorAnalytics)
pacman::p_load(tidyverse,tidyquant,FFdownload,FactorAnalytics,PerformanceAnalytics)
pacman::p_load(tidyverse,tidyquant,FFdownload,PortfolioAnalytics,nloptr)
pacman::p_load(tidyverse,tidyquant,PortfolioAnalytics,nloptr,tsibble,matrixcalc,Matrix,timetk,xts)
## Important Function

#       fitTsfm
#   
#     fitTsfm(asset.names, factor.names, data, fit.method, variable.selection, ...):
#     
#     Fits a time series (a.k.a. macroeconomic) factor model for one or more asset returns or excess
#     returns using time series regression. Least squares (LS), discounted least squares (DLS) and
#     robust regression fitting are possible. Variable selection methods include "stepwise", "subsets" and "lars". An object of class "tsfm" containing the
#     fitted objects, estimated coefficients, R-squared and residual volatility is returned.

Please remember to put your assignment solutions in rmd format using many chunks and putting readable text in between, similar to my examples given in Research Methods and Assignment 1!

For all exercises: Please use the Assignment-Forum to post your questions, I will try my best to help you along! If you follow the vignettes from factorAnalytics, wherever it says z.score=T, please exchange it for either z.score='crossSection' or z.score='timeSeries' depending on the task at hand.

Exercise 1: Estimating the CAPM (from A05)

In this exercise we want to estimate the CAPM. Please read carefully through the two documents provided (right hand side: files). Then we start to collect the necessary data:

  1. From Datastream get the last 10 years of data from the 100 stocks of the S&P100 using the list LS&P100I (S&P 100): total return index (RI) and market cap (MV)
  2. Further import the Fama-French-Factors from Kenneth Frenchs homepage (monthly, e.g. using FFdownload). From both datasets we select data for the last (available) 60 months, calculate returns (simple percentage) for the US-Stocks and eliminate those stocks that have NAs for this period.
  3. Now subtract the risk-free rate from all the stocks. Then estimate each stocks beta with the market: Regress all stock excess returns on the market excess return and save all betas (optimally use mutate and map in combination with lm). Estimate the mean-return for each stock and plot the return/beta-combinations. Create the security market line and include it in the plot! What do you find?
  4. In a next step (following both documents), we sort the stocks according to their beta and build ten value-weighted portfolios (with more or less the same number of stocks). Repeat a) for the ten portfolios. What do you observe?
  5. In the third step you follow page 6-8 of the second document and estimate the second-pass regression with the market and then market & idiosyncratic risk. What do you observe? Present all your results in a similar fashion as in the document.

Exercise 2: Calculating and checking the CAPM cont. (from A05)

pacman::p_load(tidyverse,tidyquant,FFdownload,PortfolioAnalytics,nloptr,readxl,quantmod,FFdownload,timetk, dplyr, xts)

As we have seen: the CAPM for small portfolios does not work very well, and so we start using portfolios that get rid of the idiosyncratic risk! Go to Kenneth French’s Homepage again and download the following datasets: “Portfolios Formed on Market Beta” (where we will use 10 monthly value weighted portfolios formed on beta) and “25 Portfolios Formed on Size and Market Beta” (same thing) as well as the market factor and rf (as before). Now we are going to check the CAPM like famous researchers have done it! We can use returns as they are in the files (simple returns)!

inputlist<-c("F-F_Research_Data_Faktors_CSV.zip","Portfolios_Formed_on_BETA_CSV.zip")
             
#Now process only these files if they can be matched (download only)
FFdownload(output_file = "FFdata.RData", inputlist = inputlist, exclude_daily=TRUE)
Step 1: getting list of all the csv-zip-files!

Step 2: Downloading 2 zip-files

trying URL 'http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/F-F_Research_Data_Factors_CSV.zip'
trying URL 'http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/Portfolios_Formed_on_BETA_CSV.zip'
Step 3: Start processing 2 csv-files

  |                                                                                                                 
  |                                                                                                           |   0%
  |                                                                                                                 
  |======================================================                                                     |  50%
  |                                                                                                                 
  |===========================================================================================================| 100%
load("FFdata.RData")
portf_mkt_betatest<-(FFdownload$x_Portfolios_Formed_on_BETA$monthly$value_weighted_returns)

portf_mkt_betatest
          Lo.20  Qnt.2  Qnt.3  Qnt.4  Hi.20  Lo.10  Dec.2  Dec.3  Dec.4  Dec.5  Dec.6  Dec.7  Dec.8  Dec.9  Hi.10
Jul 1963   1.13  -0.08  -0.97  -0.94  -1.41   1.35   0.77   0.08  -0.24  -0.69  -1.20  -0.49  -1.39  -1.94  -0.77
Aug 1963   3.66   4.77   6.46   6.23   9.69   3.52   3.89   4.29   5.25   5.23   7.55   7.57   4.91   9.04  10.47
Sep 1963  -2.78  -0.76  -0.78  -0.81  -2.73  -3.09  -2.24  -0.54  -0.97  -1.37  -0.27  -0.63  -1.00  -1.92  -3.68
Oct 1963   0.74   3.56   2.03   5.70   3.06   1.25  -0.12   2.00   5.12   2.32   1.78   6.63   4.78   3.10   3.01
Nov 1963  -0.63  -0.26  -0.81  -0.92   0.13  -0.91  -0.15   1.60  -2.05  -0.94  -0.69  -1.32  -0.51  -0.20   0.52
Dec 1963   2.66   2.07   2.66   2.34   0.75   3.86   0.63   2.31   1.83   3.00   2.36   1.25   3.45   0.30   1.28
Jan 1964   2.89   2.75   2.40   3.62   1.56   3.74   1.41   2.74   2.76   1.76   2.95   2.88   4.35   2.07   0.96
Feb 1964   1.31   1.38   1.98   2.77   3.15   1.08   1.72   0.62   2.14   2.36   1.66   1.74   3.78   2.53   3.89
Mar 1964   0.95   0.63   2.26   3.11   6.00   1.05   0.76   0.05   1.20   2.92   1.69   2.28   3.90   5.89   6.12
Apr 1964   2.35   1.48  -0.38  -2.46  -3.26   2.65   1.81   1.57   1.38  -0.89   0.07  -2.26  -2.65  -1.79  -4.98
May 1964   1.67   1.53   1.42   1.93   1.37   1.64   1.71   0.23   2.81   2.08   0.84   0.71   3.09   1.41   1.33
Jun 1964   1.76   2.04   1.27   1.00   1.92   1.52   2.20   3.81   0.34   1.14   1.39   2.07   0.01   2.14   1.66
Jul 1964   1.38   3.64   2.23   0.18   0.95   4.07   0.67   4.86   2.24   3.43   1.02   1.07  -0.54   1.22   0.48
Aug 1964  -0.96  -0.49  -1.28  -2.12  -2.09   1.34  -1.59   0.13  -1.23  -1.92  -0.62  -1.56  -2.59  -1.79  -2.65
Sep 1964   1.55   3.35   3.65   2.99   5.73   2.88   1.17   3.48   3.19   3.58   3.72   3.08   2.91   5.75   5.68
Oct 1964   1.00   1.58   1.32  -1.10   0.43   1.17   0.95   0.94   2.33   1.46   1.18   0.64  -2.54  -0.42   1.97
Nov 1964   0.35   0.27   1.45  -0.89  -2.73   1.30   0.08  -0.26   0.89   1.96   0.93  -0.09  -1.57  -2.96  -2.31
Dec 1964   1.50   0.18   0.06  -0.37  -0.80  -0.11   1.96   0.58  -0.28   0.09   0.04  -1.00   0.19  -1.00  -0.45
Jan 1965   1.29   3.67   4.65   6.41   6.81   2.89   0.84   4.02   3.27   5.55   3.71   4.84   7.76   6.19   7.90
Feb 1965  -0.35  -0.69   0.84   3.07   4.34   1.17  -0.79  -0.01  -1.49  -0.43   2.19   3.00   3.12   3.86   5.18
Mar 1965  -1.41  -0.42  -2.08  -0.69  -0.33  -0.01  -1.81   0.09  -1.03  -2.62  -1.53  -1.15  -0.30  -0.20  -0.56
Apr 1965   1.98   3.83   4.05   3.89   5.13   1.29   2.19   4.80   2.67   2.07   6.06   2.06   5.40   5.31   4.79
May 1965   0.86  -1.69   0.29  -0.53  -1.40  -0.10   1.14  -2.46  -0.74   2.11  -1.50  -0.49  -0.57  -1.49  -1.24
Jun 1965  -3.79  -4.05  -5.06  -6.16  -9.29  -5.06  -3.42  -5.44  -2.36  -5.21  -4.91  -6.62  -5.80  -8.59 -10.53
Jul 1965   1.92   0.83   0.81   2.45   5.59   2.10   1.78   1.48   0.50   0.65   0.97   0.80   3.64   4.62   6.67
Aug 1965   1.29   2.52   4.11   4.36   7.40   1.16   1.39   1.62   3.00   3.63   4.58   3.47   4.97   5.55   9.43
Sep 1965   4.49   2.17   2.42   2.22   5.51   4.92   4.18   3.13   1.68   2.78   2.08   2.48   2.04   5.65   5.37
Oct 1965   2.55   1.88   2.64   4.05   6.96   1.76   3.14   2.89   1.35   2.14   3.13   3.89   4.17   5.99   7.99
Nov 1965  -0.77  -2.07   1.37   2.14   6.46   1.35  -2.32  -0.79  -2.76   2.02   0.74   3.27   1.36   4.69   8.30
Dec 1965   0.58   1.09   0.92   1.70   4.76   0.63   0.54   0.71   1.29   0.67   1.17   3.42   0.48   4.44   5.07
Jan 1966   0.39  -0.34   0.87   1.93   6.28   0.98  -0.06   0.04  -0.55   1.61   0.14   1.97   1.90   6.11   6.44
Feb 1966  -2.91  -2.03  -0.86   1.39   5.70  -3.51  -2.44  -3.03  -1.49  -1.01  -0.70  -0.45   2.72   3.07   8.34
Mar 1966  -2.41  -2.20  -3.15  -0.86  -0.65  -1.34  -3.23  -3.04  -1.74  -2.56  -3.75  -2.00  -0.06   0.04  -1.30
Apr 1966   1.37   1.51   1.75   4.78   5.36   2.70   0.33   0.31   2.15   1.44   2.05   5.15   4.51   5.35   5.37
May 1966  -4.78  -3.59  -4.99  -5.16 -11.16  -4.84  -4.73  -3.84  -3.47  -4.97  -5.01  -5.22  -5.12  -9.91 -12.37
Jun 1966  -2.04  -1.39  -1.73   0.09   1.99  -2.09  -2.00  -2.95  -0.58  -1.51  -1.95   1.25  -0.71   0.32   3.64
Jul 1966  -0.55  -1.05  -0.17  -2.74  -2.11  -0.36  -0.68  -0.48  -1.38  -0.32  -0.05  -2.14  -3.26  -2.32  -1.94
Aug 1966  -6.72  -7.59  -7.62  -7.28  -8.71  -6.88  -6.61  -8.11  -7.29  -7.04  -8.08  -5.42  -8.89  -8.62  -8.79
Sep 1966   1.61   0.17  -0.94  -2.27  -5.22   1.59   1.63   0.16   0.18  -1.67  -0.35  -2.59  -1.99  -5.03  -5.38
Oct 1966   7.44   5.05   4.68   2.47  -2.79   5.78   8.52   7.23   3.81   5.31   4.17   2.03   2.86  -0.61  -4.57
Nov 1966  -1.50  -0.82   1.87   6.04  10.94  -1.09  -1.76   0.05  -1.33   1.48   2.17   2.15   9.47   8.49  13.02
Dec 1966   1.15  -0.12   1.45  -0.53   0.57  -0.16   1.98   1.03  -0.81   2.10   0.93  -0.81  -0.30   1.68  -0.34
Jan 1967   4.98   7.80   8.56  11.01  14.38   3.78   5.73   7.42   8.03   9.56   7.74  10.99  11.03  13.48  15.12
Feb 1967  -0.02   0.30   0.80   3.33   2.37  -0.89   0.51   0.64   0.09   1.20   0.47   1.40   4.90   1.32   3.23
Mar 1967   3.61   3.12   5.38   5.34   5.64   4.54   3.04   2.93   3.24   6.20   4.71   5.59   5.15   5.86   5.46
Apr 1967   1.24   4.79   3.90   6.28   6.21   1.22   1.25   2.78   6.00   4.13   3.71   5.85   6.62   5.26   6.97
May 1967  -3.36  -4.46  -4.06  -4.18  -3.92  -1.86  -4.28  -2.68  -5.50  -3.24  -4.74  -4.27  -4.11  -5.80  -2.44
Jun 1967   1.99   1.01   2.92   3.86   4.44   1.85   2.08   1.54   0.69   3.02   2.83   2.82   4.67   4.01   4.76
Jul 1967   2.37   5.97   5.02   7.38   7.80   0.48   4.48   5.30   6.39   6.18   3.65   7.04   7.68   6.07   9.50
Aug 1967  -1.17  -0.33  -0.45   0.10  -0.37  -1.27  -1.07   0.20  -0.64   0.32  -1.37  -0.39   0.54  -0.45  -0.29
Sep 1967   2.33   2.54   5.02   2.70   3.97   1.29   3.45   1.62   3.09   3.66   6.67   2.74   2.67   4.61   3.37
Oct 1967  -2.62  -4.06  -1.63  -3.49  -2.68  -3.69  -1.49  -4.67  -3.71  -5.18   2.55  -4.57  -2.56  -1.93  -3.41
Nov 1967   1.32   1.06   0.16   0.65   0.02   0.89   1.75   0.77   1.23  -0.81   1.21   2.22  -0.69  -0.94   0.97
Dec 1967   2.35   3.10   3.15   4.09   5.37   2.56   2.14   5.39   1.79   3.23   3.06   6.24   2.21   4.52   6.19
Jan 1968  -0.67  -3.13  -4.75  -6.50  -5.94   0.30  -1.66  -1.05  -4.35  -3.06  -6.56  -4.74  -8.10  -5.58  -6.29
Feb 1968  -1.98  -3.06  -2.99  -4.05  -6.69  -1.95  -2.01  -2.74  -3.26  -2.63  -3.39  -3.61  -4.46  -6.67  -6.72
Mar 1968  -0.86   0.45   1.82   0.93   2.52  -1.26  -0.44  -0.26   0.88   0.16   3.66   0.48   1.37   2.74   2.33
Apr 1968   4.82   9.19  10.78  12.37  15.00   4.65   5.01   8.21   9.77  10.23  11.35  11.89  12.82  14.07  15.87
May 1968   0.76   2.16   2.94   3.87   6.60   1.05   0.46   2.82   1.78   1.55   4.39   5.60   2.27   7.04   6.21
Jun 1968   3.20   1.60   0.23  -0.75  -0.50   4.27   2.09   4.10   0.12   0.99  -0.53   0.66  -2.10   0.70  -1.61
Jul 1968   1.70  -3.92  -3.96  -4.56  -4.12   3.23  -0.55  -4.22  -3.69  -3.60  -4.53  -4.95  -4.04  -3.92  -4.32
Aug 1968   1.09   1.72   1.57   3.49   2.92   0.95   1.31   2.21   1.33   1.41   1.82   3.98   2.82   2.05   3.78
Sep 1968   2.73   4.05   5.31   5.47   7.40   1.75   4.26   4.95   3.35   5.12   5.61   5.24   5.79   6.26   8.53
Oct 1968   2.10  -1.02   1.98   1.06  -0.02   2.43   1.60  -1.03  -1.01   3.02   0.40   0.66   1.60   1.24  -1.23
Nov 1968   6.38   5.34   3.85   6.02   9.82   6.88   5.61   3.79   6.57   1.99   6.74   5.40   6.88   8.76  10.87
Dec 1968  -4.05  -3.69  -2.96  -3.98  -2.45  -4.67  -3.08  -2.79  -4.39  -2.73  -3.29  -4.62  -3.13  -2.90  -2.01
 [ reached getOption("max.print") -- omitted 621 rows ]
#Download the Portfolios from Kenneth French's Homepage
portf_mkt_beta <- "https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/Portfolios_Formed_on_BETA_CSV.zip"
 portf_mkt_beta_csv <- "Portfolios_Formed_on_BETA.csv"
 temp <- tempfile()
download.file(portf_mkt_beta, temp, quiet = TRUE)
portf_mkt_beta <- read_csv(unz(temp, portf_mkt_beta_csv), skip = 15, quote = "\",") %>%
  dplyr::rename(date = "X1") %>%
  mutate_at(vars(-date), as.numeric) %>%
  mutate(date = rollback(ymd(parse_date_time(date, "%Y%m") + months(1))))%>%
  filter(date >= first('1964-01-01') & date <= '2019-12-31')
Missing column names filled in: 'X1' [1]
── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────
cols(
  X1 = col_character(),
  `Lo 20` = col_character(),
  `Qnt 2` = col_character(),
  `Qnt 3` = col_character(),
  `Qnt 4` = col_character(),
  `Hi 20` = col_character(),
  `Lo 10` = col_character(),
  `Dec 2` = col_character(),
  `Dec 3` = col_character(),
  `Dec 4` = col_character(),
  `Dec 5` = col_character(),
  `Dec 6` = col_character(),
  `Dec 7` = col_character(),
  `Dec 8` = col_character(),
  `Dec 9` = col_character(),
  `Hi 10` = col_character()
)

7 parsing failures.
 row col   expected    actual         file
 688  -- 16 columns 1 columns <connection>
1377  -- 16 columns 1 columns <connection>
1435  -- 16 columns 1 columns <connection>
1493  -- 16 columns 1 columns <connection>
2182  -- 16 columns 1 columns <connection>
.... ... .......... ......... ............
See problems(...) for more details.
Problem with `mutate()` input `Lo 20`.
ℹ NAs introduced by coercion
ℹ Input `Lo 20` is `.Primitive("as.double")(`Lo 20`)`.NAs introduced by coercionProblem with `mutate()` input `Qnt 2`.
ℹ NAs introduced by coercion
ℹ Input `Qnt 2` is `.Primitive("as.double")(`Qnt 2`)`.NAs introduced by coercionProblem with `mutate()` input `Qnt 3`.
ℹ NAs introduced by coercion
ℹ Input `Qnt 3` is `.Primitive("as.double")(`Qnt 3`)`.NAs introduced by coercionProblem with `mutate()` input `Qnt 4`.
ℹ NAs introduced by coercion
ℹ Input `Qnt 4` is `.Primitive("as.double")(`Qnt 4`)`.NAs introduced by coercionProblem with `mutate()` input `Hi 20`.
ℹ NAs introduced by coercion
ℹ Input `Hi 20` is `.Primitive("as.double")(`Hi 20`)`.NAs introduced by coercionProblem with `mutate()` input `Lo 10`.
ℹ NAs introduced by coercion
ℹ Input `Lo 10` is `.Primitive("as.double")(`Lo 10`)`.NAs introduced by coercionProblem with `mutate()` input `Dec 2`.
ℹ NAs introduced by coercion
ℹ Input `Dec 2` is `.Primitive("as.double")(`Dec 2`)`.NAs introduced by coercionProblem with `mutate()` input `Dec 3`.
ℹ NAs introduced by coercion
ℹ Input `Dec 3` is `.Primitive("as.double")(`Dec 3`)`.NAs introduced by coercionProblem with `mutate()` input `Dec 4`.
ℹ NAs introduced by coercion
ℹ Input `Dec 4` is `.Primitive("as.double")(`Dec 4`)`.NAs introduced by coercionProblem with `mutate()` input `Dec 5`.
ℹ NAs introduced by coercion
ℹ Input `Dec 5` is `.Primitive("as.double")(`Dec 5`)`.NAs introduced by coercionProblem with `mutate()` input `Dec 6`.
ℹ NAs introduced by coercion
ℹ Input `Dec 6` is `.Primitive("as.double")(`Dec 6`)`.NAs introduced by coercionProblem with `mutate()` input `Dec 7`.
ℹ NAs introduced by coercion
ℹ Input `Dec 7` is `.Primitive("as.double")(`Dec 7`)`.NAs introduced by coercionProblem with `mutate()` input `Dec 8`.
ℹ NAs introduced by coercion
ℹ Input `Dec 8` is `.Primitive("as.double")(`Dec 8`)`.NAs introduced by coercionProblem with `mutate()` input `Dec 9`.
ℹ NAs introduced by coercion
ℹ Input `Dec 9` is `.Primitive("as.double")(`Dec 9`)`.NAs introduced by coercionProblem with `mutate()` input `Hi 10`.
ℹ NAs introduced by coercion
ℹ Input `Hi 10` is `.Primitive("as.double")(`Hi 10`)`.NAs introduced by coercion 177 failed to parse.
#Download the market factor and rf (Fama/French 3 Research Factors)
mkt_factors <- "https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/F-F_Research_Data_Factors_CSV.zip"
 mkt_factors_csv <- "F-F_Research_Data_Factors.CSV"
 temp <- tempfile()
download.file(mkt_factors, temp, quiet = TRUE)
mkt_factors <- read_csv(unz(temp, mkt_factors_csv), skip = 3, quote = "\",") %>%
  dplyr::rename(date = X1) %>%
  mutate_at(vars(-date), as.numeric) %>%
  mutate(date = rollback(ymd(parse_date_time(date, "%Y%m") + months(1)))) %>%
  filter(date >= first('1964-01-01') & date <= '2019-12-31')
Missing column names filled in: 'X1' [1]
── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────
cols(
  X1 = col_double(),
  `Mkt-RF` = col_double(),
  SMB = col_double(),
  HML = col_double(),
  RF = col_double()
)

8 parsing failures.
 row    col  expected                           actual         file
1132 X1     a double  Annual Factors: January-December <connection>
1132 NA     5 columns 1 columns                        <connection>
1133 Mkt-RF a double  Mkt-RF                           <connection>
1133 SMB    a double  SMB                              <connection>
1133 HML    a double  HML                              <connection>
.... ...... ......... ................................ ............
See problems(...) for more details.
 93 failed to parse.
  1. Subtract the risk-free rate from the first set of 10 portfolios (only sorted on beta) (Lo 10,., Hi 10) and estimate each stocks beta with the market. Estimate the mean-return for each stock and plot the return/beta-combinations. Create the security market line and include it in the plot! What do you find? (You can split the file in 2-3 different time blocks and see if something changes). * Now we are done with the first-pass regression.*

Subtract the risk-free rate from the first set of 10 portfolios (only sorted on beta) (Lo 10,., Hi 10) and estimate each stocks beta with the market.

#join data
ten_portf <- portf_mkt_beta[1:672, -c(2:6)]
ten_portf_joined <- left_join(mkt_factors, ten_portf)
Joining, by = "date"
mkt_factors
ten_portf
ten_portf_joined
NA
#substract Risk-Free-Rate
ten_portf_rf <- mutate(ten_portf_joined, Lo10rf = Lo10 - RF, Dec2rf = Dec2 - RF, Dec3rf = Dec3 - RF, Dec4rf = Dec4 - RF, Dec5rf = Dec5 -RF, Dec6rf = Dec6 - RF, Dec7rf = Dec7 - RF, Dec8rf = Dec8 - RF, De9rf = Dec9 - RF, Hi10rf = Hi10 - RF)
ten_portf_rf <- ten_portf_rf[-2:-15]

view(ten_portf_rf)
ten_portf_rf
Non-numeric columns being dropped: date
?lm()
#Calculate Betas for each portfolio
betas_ten_portf_lm <- lm(ten_portf_rf_xts ~ mkt_factors_xts[, 1])
betas_ten_portf_lm

Call:
lm(formula = ten_portf_rf_xts ~ mkt_factors_xts[, 1])

Coefficients:
                      Lo10rf    Dec2rf    Dec3rf    Dec4rf    Dec5rf    Dec6rf    Dec7rf    Dec8rf    De9rf   
(Intercept)            0.23458   0.13725   0.13813   0.15888   0.01110   0.05621  -0.09574  -0.01230  -0.11817
mkt_factors_xts[, 1]   0.61008   0.73518   0.83572   0.97113   1.02007   1.08413   1.15670   1.27953   1.38876
                      Hi10rf  
(Intercept)           -0.24513
mkt_factors_xts[, 1]   1.61253
betas_ten_portf <- CAPM.beta(Ra = ten_portf_rf_xts, Rb = mkt_factors_xts[, 1], Rf = 0)
betas_ten_portf
                Lo10rf    Dec2rf    Dec3rf   Dec4rf   Dec5rf   Dec6rf   Dec7rf   Dec8rf   De9rf   Hi10rf
Beta: Mkt-RF 0.6100834 0.7351849 0.8357215 0.971132 1.020072 1.084128 1.156701 1.279531 1.38876 1.612531

Estimate the mean-return for each stock and plot the return/beta-combinations.

#Estimate Mean Return
mean_ten_portf_rf_xts <- as.data.frame(lapply(ten_portf_rf_xts, FUN=mean))
mean_ten_portf_rf_xts

#Plot the return/beta-combinations
plot.default(x = betas_ten_portf, xlim=c(0, 2),
             y = mean_ten_portf_rf_xts, ylim=c(0, 1),
             xlab = "Beta", ylab = "Mean Return",
             main = "Return/Beta-combinations")

Create the security market line and include it in the plot! What do you find?

mean_mkt <- as.data.frame(lapply(mkt_factors_xts[, 1], FUN=mean))
y_mkt <- mean_mkt[1, 1]
plot.default(x = betas_ten_portf, xlim=c(0, 2),
             y = mean_ten_portf_rf_xts, ylim=c(0, 1),
             xlab = "Beta", ylab = "Mean Return",
             main = "Return/Beta-combinations",
             abline(0, y_mkt))

plot.default(x = betas_ten_portf, xlim=c(0, 2), 
             y = mean_ten_portf_rf_xts, ylim=c(0, 10), 
             xlab = "Beta", ylab = "Mean Return",
             main = "Return/Beta-combinations",
             abline(0, y_mkt))


#summary
summary_CAPM_ten_portf <- (table.CAPM(Ra = ten_portf_rf_xts, Rb = mkt_factors_xts[, 1], Rf = 0)[1:9, ])

(You can split the file in 2-3 different time blocks and see if something changes). * Now we are done with the first-pass regression.*

#look for first 10 years
ten_portf_rf_10yrs_xts <- ten_portf_rf[1:120, ] %>%
  tk_xts(date_var = date, silent = TRUE)
betas_ten_portf_rf_10yrs <- CAPM.beta(Ra = ten_portf_rf_10yrs_xts, Rb = mkt_factors_xts[1:120, 1], Rf = 0)
mean_ten_portf_rf_10yrs_xts <- as.data.frame(lapply(ten_portf_rf_10yrs_xts, FUN=mean))
mean_mkt_10yrs <- as.data.frame(lapply(mkt_factors_xts[1:120, 1], FUN=mean))
y_mkt_10yrs <- mean_mkt_10yrs[1, 1]
plot.default(x = betas_ten_portf_rf_10yrs, xlim=c(0, 2),
             y = mean_ten_portf_rf_10yrs_xts, ylim=c(0, 1),
             xlab = "Beta", ylab = "Mean Return",
             main = "Return/Beta-combinations 1964-1974",
             abline(0, y_mkt_10yrs))

summary_CAPM_ten_portf_10yrs <- (table.CAPM(Ra = ten_portf_rf_xts[1:120, ], Rb = mkt_factors_xts[1:120, 1], Rf = 0)[1:9, ])
summary_CAPM_ten_portf_10yrs

  1. In the second-pass regression we now regress the average stock returns on the betas estimated before. What do you find in the coefficients and does this contradict the CAPM? Try different time periods again and see what you find. (all of the interpretations are in BKM pp.416f).
betas_ten_portf
                Lo10rf    Dec2rf    Dec3rf   Dec4rf   Dec5rf   Dec6rf   Dec7rf   Dec8rf   De9rf   Hi10rf
Beta: Mkt-RF 0.6100834 0.7351849 0.8357215 0.971132 1.020072 1.084128 1.156701 1.279531 1.38876 1.612531
#There are a number of reasons we expect might the CAPM to fail:
#1. Imperfect measures of the market portfolio
#2. Beta is an incomplete measure of risk
#3. Tax effects
#4. Non - normality of returns
#5. No riskless asset
#6. Divergent borrowing and lending rates

There are a number of reasons we expect might the CAPM to fail: 1. Imperfect measures of the market portfolio 2. Beta is an incomplete measure of risk 3. Tax effects 4. Non - normality of returns 5. No riskless asset 6. Divergent borrowing and lending rates

  1. Now do the extended second pass regression (regress on betas and residual-sds that you can extract from the regression) and see what you find for different periods. Interpret according to concept check 13.2. One of the (many) problems of the CAPM can be the correlation between residual variances and betas. Calculate and interpret.
#Look at a) -> We now do it with the mean return of every portfolio combined... 

#1964-2019
com_mean_ten_portf_rf <- sum(mean_ten_portf_rf_xts)/10
mean_betas_ten_portf <- sum(betas_ten_portf)/10
plot.default(x = mean_betas_ten_portf, xlim=c(0, 2),
             y = com_mean_ten_portf_rf, ylim=c(0, 2),
             xlab = "Beta", ylab = "Mean Return",
             main = "Return/Beta-combinations 10 Portfolios 1964-2019",
             abline(0, y_mkt))

NA
NA

  1. Try again with 25 portfolios sorted on size and beta. What do you find? Is that interesting?
inputlist1<-c("F-F_Research_Data_Faktors_CSV.zip","25_Portfolios_Formed_on_Size_and Market_Beta_CSV.zip")
             
#Now process only these files if they can be matched (download only)
FFdownload(output_file = "FFdata.RData", inputlist = inputlist1, exclude_daily=TRUE)
Step 1: getting list of all the csv-zip-files!

Step 2: Downloading 2 zip-files

trying URL 'http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/F-F_Research_Data_Factors_CSV.zip'
trying URL 'http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/Portfolios_Formed_on_ME_Wout_Div_CSV.zip'
Step 3: Start processing 2 csv-files

  |                                                                                                                 
  |                                                                                                           |   0%
  |                                                                                                                 
  |======================================================                                                     |  50%
  |                                                                                                                 
  |===========================================================================================================| 100%
load("FFdata.RData")
twentyfive_portf<-(FFdownload$x_25_Portfolios_Formed_on_Size_and_Market_Beta$monthly$value_weighted_returns)

twentyfive_portf
NULL
 
download.file(portf_mkt_beta, temp, quiet = TRUE)
Error in download.file(portf_mkt_beta, temp, quiet = TRUE) : 
  invalid 'url' argument
twentyfive_portf
NULL
#join data
twentyfive_portf <- portf_mkt_beta[1:672, -c(7:16)]
twentyfive_portf_joined <- left_join(mkt_factors, twentyfive_portf)
Joining, by = "date"
#substract Risk-Free-Rate
twentyfive_portf_rf <- mutate(twentyfive_portf_joined, Lo20rf = Lo20 - RF, Qnt2rf = Qnt2 - RF, Qnt3rf = Qnt3 - RF, Qnt4rf = Qnt4 - RF, Hi20rf = Hi20 - RF)
twentyfive_portf_rf <- twentyfive_portf_rf[-2:-10]

#substract Risk-Free-Rate
ten_portf_rf <- mutate(ten_portf_joined, Lo10rf = Lo10 - RF, Dec2rf = Dec2 - RF, Dec3rf = Dec3 - RF, Dec4rf = Dec4 - RF, Dec5rf = Dec5 -RF, Dec6rf = Dec6 - RF, Dec7rf = Dec7 - RF, Dec8rf = Dec8 - RF, De9rf = Dec9 - RF, Hi10rf = Hi10 - RF)
ten_portf_rf <- ten_portf_rf[-2:-15]

view(ten_portf_rf)
ten_portf_rf
Non-numeric columns being dropped: date
?lm()
#Calculate Betas for each portfolio
betas_ten_portf_lm <- lm(ten_portf_rf_xts ~ mkt_factors_xts[, 1])
betas_ten_portf_lm

Call:
lm(formula = ten_portf_rf_xts ~ mkt_factors_xts[, 1])

Coefficients:
                      Lo10rf    Dec2rf    Dec3rf    Dec4rf    Dec5rf    Dec6rf    Dec7rf    Dec8rf    De9rf   
(Intercept)            0.23458   0.13725   0.13813   0.15888   0.01110   0.05621  -0.09574  -0.01230  -0.11817
mkt_factors_xts[, 1]   0.61008   0.73518   0.83572   0.97113   1.02007   1.08413   1.15670   1.27953   1.38876
                      Hi10rf  
(Intercept)           -0.24513
mkt_factors_xts[, 1]   1.61253
betas_ten_portf <- CAPM.beta(Ra = ten_portf_rf_xts, Rb = mkt_factors_xts[, 1], Rf = 0)
betas_ten_portf
                Lo10rf    Dec2rf    Dec3rf   Dec4rf   Dec5rf   Dec6rf   Dec7rf   Dec8rf   De9rf   Hi10rf
Beta: Mkt-RF 0.6100834 0.7351849 0.8357215 0.971132 1.020072 1.084128 1.156701 1.279531 1.38876 1.612531

Estimate the mean-return for each stock and plot the return/beta-combinations.

#Estimate Mean Return
mean_ten_portf_rf_xts <- as.data.frame(lapply(ten_portf_rf_xts, FUN=mean))
mean_ten_portf_rf_xts

#Plot the return/beta-combinations
plot.default(x = betas_ten_portf, xlim=c(0, 2),
             y = mean_ten_portf_rf_xts, ylim=c(0, 1),
             xlab = "Beta", ylab = "Mean Return",
             main = "Return/Beta-combinations")

Create the security market line and include it in the plot! What do you find?

mean_mkt <- as.data.frame(lapply(mkt_factors_xts[, 1], FUN=mean))
y_mkt <- mean_mkt[1, 1]
plot.default(x = betas_ten_portf, xlim=c(0, 2),
             y = mean_ten_portf_rf_xts, ylim=c(0, 1),
             xlab = "Beta", ylab = "Mean Return",
             main = "Return/Beta-combinations",
             abline(0, y_mkt))



#

(You can split the file in 2-3 different time blocks and see if something changes). * Now we are done with the first-pass regression.*

#look for first 10 years
ten_portf_rf_10yrs_xts <- ten_portf_rf[1:120, ] %>%
  tk_xts(date_var = date, silent = TRUE)
betas_ten_portf_rf_10yrs <- CAPM.beta(Ra = ten_portf_rf_10yrs_xts, Rb = mkt_factors_xts[1:120, 1], Rf = 0)
mean_ten_portf_rf_10yrs_xts <- as.data.frame(lapply(ten_portf_rf_10yrs_xts, FUN=mean))
mean_mkt_10yrs <- as.data.frame(lapply(mkt_factors_xts[1:120, 1], FUN=mean))
y_mkt_10yrs <- mean_mkt_10yrs[1, 1]
plot.default(x = betas_ten_portf_rf_10yrs, xlim=c(0, 2),
             y = mean_ten_portf_rf_10yrs_xts, ylim=c(0, 1),
             xlab = "Beta", ylab = "Mean Return",
             main = "Return/Beta-combinations 1964-1974",
             abline(0, y_mkt_10yrs))

summary_CAPM_ten_portf_10yrs <- (table.CAPM(Ra = ten_portf_rf_xts[1:120, ], Rb = mkt_factors_xts[1:120, 1], Rf = 0)[1:9, ])
summary_CAPM_ten_portf_10yrs

  1. In the second-pass regression we now regress the average stock returns on the betas estimated before. What do you find in the coefficients and does this contradict the CAPM? Try different time periods again and see what you find. (all of the interpretations are in BKM pp.416f).

There are a number of reasons we expect might the CAPM to fail: 1. Imperfect measures of the market portfolio 2. Beta is an incomplete measure of risk 3. Tax effects 4. Non - normality of returns 5. No riskless asset 6. Divergent borrowing and lending rates

  1. Now do the extended second pass regression (regress on betas and residual-sds that you can extract from the regression) and see what you find for different periods. Interpret according to concept check 13.2. One of the (many) problems of the CAPM can be the correlation between residual variances and betas. Calculate and interpret.
#Look at a) -> We now do it with the mean return of every portfolio combined... 

#1964-2019
com_mean_ten_portf_rf <- sum(mean_ten_portf_rf_xts)/10
mean_betas_ten_portf <- sum(betas_ten_portf)/10
plot.default(x = mean_betas_ten_portf, xlim=c(0, 2),
             y = com_mean_ten_portf_rf, ylim=c(0, 2),
             xlab = "Beta", ylab = "Mean Return",
             main = "Return/Beta-combinations 10 Portfolios 1964-2019",
             abline(0, y_mkt))

NA
NA

Error in merge(residual_1964_2018[1, 1], residual_1964_1974[1, 1]) : 
  object 'residual_1964_2018' not found
  1. Try again with 25 portfolios sorted on size and beta. What do you find? Is that interesting?
#join data
twentyfive_portf <- portf_mkt_beta[1:672, -c(7:16)]
twentyfive_portf_joined <- left_join(mkt_factors, twentyfive_portf)
Joining, by = "date"
#substract Risk-Free-Rate
twentyfive_portf_rf <- mutate(twentyfive_portf_joined, Lo20rf = Lo20 - RF, Qnt2rf = Qnt2 - RF, Qnt3rf = Qnt3 - RF, Qnt4rf = Qnt4 - RF, Hi20rf = Hi20 - RF)
twentyfive_portf_rf <- twentyfive_portf_rf[-2:-10]

The purpose of the further assignments is less programming-related (you can copy most of the code), but to receive a positive grade I want you to dig into the referenced literature and be able to explain everything that you do very detailed in the text and your presentation (what do you do, what is the result and how do you intepret the result). After doing this - given the data - you should be perfectly able to estimate/interpret any type of factor model.

Exercise 3: Statistical Factor Models

library(timetk)
SP500 <- tq_index("SP500")
Getting holdings for SP500
NASDAQ <- tq_exchange("NASDAQ")
Getting data...
NYSE <- tq_exchange("NYSE") 
Getting data...
stocks.selection <- SP500 %>% 
  inner_join(rbind(NYSE,NASDAQ) %>% select(symbol,last.sale.price,market.cap,ipo.year),by=c("symbol")) %>%
  filter(ipo.year<2000&!is.na(market.cap)) %>% 
  arrange(desc(weight)) %>% 
  slice(1:10)
stocks.selection

These are the returns of the selected stocks.

stocks.returns <- stocks.selection$symbol %>%
    tq_get(get  = "stock.prices",
           from = "2000-01-01",
           to   = "2019-12-31") %>%
    group_by(symbol) %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = periodReturn, 
                 period     = "monthly")
stocks.returns

These are the stocks return in the xts format and also in a wide format

stocks.returns.xts <- stocks.returns%>%
                      subset( select = c(symbol,date, monthly.returns)) %>%
                      pivot_wider(names_from = symbol, 
                                  values_from = monthly.returns) %>% 
                      tk_xts(date_var = date, silent = TRUE)
colnames(stocks.returns.xts)
 [1] "AAPL" "MSFT" "AMZN" "NVDA" "ADBE" "CSCO" "QCOM" "AMGN" "UPS"  "ORCL"

Fit a statistical factor model fitSfm

Principal Component Analysis (PCA): uses the eigen decomposition of the covariance matrix of asset returns to find the first K principal components that explain the largest portion of the sample covariance matrix returns. Factor loading are then estimated using time series regression. Foctor analysis involves maximum likelihood optimization to estimate the factor loadings and the residual covarince matrix, constructing the factor realization and choosing a rotation of the coordinate system for a more meeaningful interpretion of factors

used when T>N T: Number of observations N: Number of assets

if N>T then Aymptotic Principal Component Analysis (APCA)

Principal Component Analysis

Fitting a statistical factor model with two principal components (k=2)

fit.pca <- fitSfm(stocks.returns.xts, k=2)
fit.pca 

Call:
fitSfm(data = stocks.returns.xts, k = 2)

Model dimensions:
Factors  Assets Periods 
      2      10     240 

Factor Loadings:
      F.1               F.2          
 Min.   :0.07591   Min.   :-0.55419  
 1st Qu.:0.20299   1st Qu.:-0.19298  
 Median :0.26045   Median :-0.12929  
 Mean   :0.27738   Mean   :-0.09803  
 3rd Qu.:0.33313   3rd Qu.:-0.07555  
 Max.   :0.63274   Max.   : 0.69775  

R-squared values:
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.1456  0.3751  0.4340  0.4702  0.5257  0.9705 

Residual Volatilities:
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
0.03091 0.06662 0.06980 0.06779 0.07759 0.08733 

Screenplot of eigenvalues An eigenvector of a linear transformation is a nonzero vector that changes by a scalar factor when that linear transformation is applied to it. Eigenvalues and eigenvectors allow us to “reduce” a linear operation to separate, simpler, problems.

plot(fit.pca, which=1, eig.max = 0.9)

First principal component explains about 48% of total variance. The first two components explain about 61% of total variance.

Now plotting the estimated factor returns

plot(fit.pca, which=2)

Estimated factor loadings for all assets Factor loading is the correlation coefficient for the variable and factor.


plot(fit.pca, which=3, a.sub=1:10)

First factor has all positive loadings, whereas the second factor has both positive and negative loadings.

t(fit.pca$mimic)
         AAPL       MSFT      AMZN       NVDA       ADBE      CSCO       QCOM       AMGN        UPS       ORCL
F.1 0.1151760 0.07146734 0.1385313  0.2281127 0.12173965 0.0985711 0.07831731 0.02736584 0.03149781 0.08922093
F.2 0.0280622 0.14630514 0.5653233 -0.7117659 0.06546406 0.2048660 0.29957387 0.17283115 0.11186325 0.11747694
plot(fit.pca, which=12, n.top=3)

This figure displays the top three assets with the largest and smalles weights in each factor mimicking portfolio. For the first factor, NVIDA, Amazone and Adobe have the highest weights and Amgen, UPS and Microsoft have the lowest weights. Since all weights are positive this might be construed as a market-wide factor. For the second factor, Amazon, Qualcom and Cisco have the highest weights and NVIDA, Apple and Adobe have the lowest weights.

Now plotting the correlations between assets with the top 3 largest and smallest positions in the F.1 factor mimicking portfolio

plot(fit.pca, which=13, f.sub=1, n.top=3)

Here we can see the correlations between assets with top 3 largest and smallest weight in the factor mimicking portfolio for the first principal component. Correlations are very different.

plot(fit.pca, which=13, f.sub=2, n.top=3)

Here we can see the correlations between assets with top 3 largest and smallest weight in the factor mimicking portfolio for the first principal component. Pretty high correlations overall.

S3 generic methods

all estimaded coefficients from PCA including intercept

coef(fit.pca)
       (Intercept)        F.1         F.2
AAPL  0.0094582331 0.31947608 -0.02750960
MSFT -0.0005719413 0.19823670 -0.14342409
AMZN  0.0026867443 0.38425922 -0.55419090
NVDA -0.0008413294 0.63274098  0.69774977
ADBE  0.0014031930 0.33768242 -0.06417494
CSCO -0.0084564481 0.27341732 -0.20083179
QCOM -0.0038768497 0.21723718 -0.29367465
AMGN  0.0053513795 0.07590759 -0.16942775
UPS   0.0016476700 0.08736888 -0.10966043
ORCL -0.0051641218 0.24748175 -0.11516358

compare returns data with fitted and residual values for AAPL: fit.pca

AAPL.ts <- merge(fit.pca$data[,1], fitted(fit.pca)[,1], residuals(fit.pca)[,1])

colnames(AAPL.ts) <- c("AAPL.return", "AAPL.fitted", "AAPL.residual")

tail(AAPL.ts)
           AAPL.return AAPL.fitted AAPL.residual
2019-07-31  0.07639455  0.02642587  0.0499686870
2019-08-30 -0.01646123 -0.01632520 -0.0001360339
2019-09-30  0.07296155  0.02555255  0.0474089986
2019-10-31  0.11068450  0.05780629  0.0528782135
2019-11-29  0.07755414  0.05600977  0.0215443674
2019-12-30  0.09081378  0.04953200  0.0412817802

fitted(): returns an xts data object of the component of asset returns explained by the factor model

residuals(): returns xts data object with the component of asset returns not explained by the factor model

Summary for fit.pca with HAC standard errors (allows for heteroskedasticity and autocorrelation consistent estimates and standard errors)

sum.pca <- summary(fit.pca, se.type="HAC", n.top=3)

sum.pca$sum.list[[1]]

Call:
lm(formula = AAPL ~ f)

Residuals:
             AAPL
Min    -0.5191012
1Q     -0.0364578
Median -0.0001118
3Q      0.0472573
Max     0.2924632

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)        0.009458   0.006135   1.542    0.124    
object$factorsF.1  0.319476   0.032295   9.892   <2e-16 ***
object$factorsF.2 -0.027510   0.058010  -0.474    0.636    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.08733 on 237 degrees of freedom
Multiple R-squared:  0.4426,    Adjusted R-squared:  0.4379 
F-statistic: 94.08 on 2 and 237 DF,  p-value: < 2.2e-16

factor mimicking portfolio weights

sum.pca$mimic.sum
$F.1

$F.2
NA

Factor Model Covariance and Risk Decomposition

Factor model covariance

Omega <- fmCov(fit.pca)
# return correlation plot for all assets
plot(fit.pca, which=8, a.sub=1:10)

Standard deviation decomposition

decomp <- fmSdDecomp(fit.pca)

#get the factor model standard deviation for all assets
decomp$Sd.fm
      AAPL       MSFT       AMZN       NVDA       ADBE       CSCO       QCOM       AMGN        UPS       ORCL 
0.11674807 0.08388945 0.13624535 0.17908437 0.11433920 0.09770189 0.10508420 0.07378590 0.05756518 0.09477957 
#get the component contribution to Sd
head(decomp$cSd)
            F.1          F.2  Residuals
AAPL 0.05132537 0.0001013369 0.06532137
MSFT 0.02750210 0.0038334162 0.05255393
AMZN 0.06362562 0.0352408355 0.03737889
NVDA 0.13125002 0.0425001866 0.00533416
ADBE 0.05855000 0.0005630992 0.05522610
CSCO 0.04492149 0.0064537340 0.04632666
#plotting
plot(fit.pca, which=9, f.sub=1:2, a.sub=1:10)

Value-at-Risk decomposition

decomp1 <- fmVaRDecomp(fit.pca)

#factor model Value-at-Risk
head(decomp1$VaR.fm)
      AAPL       MSFT       AMZN       NVDA       ADBE       CSCO 
-0.1511336 -0.1230763 -0.1915657 -0.2249127 -0.1601538 -0.1525801 
#Marginal factor contributions to VAR
head(decomp1$mVaR)
            F.1          F.2  Residuals
AAPL -0.2685626  0.019684759 -0.7419490
MSFT -0.2139303  0.044635093 -1.1184894
AMZN -0.2210924  0.097203372 -0.7390325
NVDA -0.2914210 -0.051684810 -0.1441595
ADBE -0.2905442  0.003866864 -0.7776361
CSCO -0.2554710  0.074042153 -1.0086633
# plotting
plot(fit.pca, which=11, f.sub=1:2, a.sub=1:10)

####Expected Shorfall decomposition

decomp2 <- fmEsDecomp(fit.pca)
# factor model Expected Shortfall
head(decomp2$ES.fm)
      AAPL       MSFT       AMZN       NVDA       ADBE       CSCO 
-0.2577662 -0.1714347 -0.2923700 -0.3138664 -0.2269914 -0.2307265 
# percentage component contribution to ES
head(decomp2$pcES)
          F.1        F.2 Residuals
AAPL 42.00512  0.3084239 57.686452
MSFT 34.03340  7.9302336 58.036365
AMZN 47.78847 27.1436084 25.067918
NVDA 81.55481 16.8396382  1.605556
ADBE 51.46756  0.8127492 47.719693
CSCO 31.64666 14.3307631 54.022580
# plotting
plot(fit.pca, which = 10, f.sub=1:2, a.sub=1:10)

Exercise 4: Timeseries Factor Models

Follow the file tsfmVignette.pdf and interpret your results.

Theorie

In a time series or macroeconomic factor model, observable economic time series such as industrial production growth rate, interest rates, market returns and inflation are used as common factors that contribute to asset returns. - For example, the famous single index model by Sharpe (1964) uses the market excess return as the common factor (captures economy-wide or market risk) for all assets and the unexplained returns in the error term represents the non-market firm specific risk. - On the other hand, Chen et al. (1986) uses a multi-factor model to find that surprise inflation, the spread between long and short-term interest rates and between high and low grade bonds are significantly priced, while the market portfolio, aggregate consumption risk and oil price risk are not priced separately.


library(FactorAnalytics)

# The following examples primarily use the managers dataset from the PerformanceAnalytics package. 
# It’s an "xts" data object with:
#                                 - 132 observations of monthly returns
#                                 - on 10 variables:
#                                     - six hypothetical asset managers, 
#                                     - 1x dhec returns (Long-Short Equity hedge fund index)
#                                     - 1x sp500 returns
#                                     - US treasury bonds 10 years (will serve as explanatory factors)
#                                     - US treasury bills 3 months (can be considered as the risk free rate)
#                                 - there are some "not available" observations (start day!)

data(managers)
Warning in tclass.xts(x) : index does not have a ‘tclass’ attribute
Warning in tclass.xts(x) : index does not have a ‘tclass’ attribute
Warning in tclass.xts(object) :
  index does not have a ‘tclass’ attribute
Warning in tzone.xts(object) : index does not have a ‘tzone’ attribute
Warning in tclass.xts(x) : index does not have a ‘tclass’ attribute
Warning in tclass.xts(x) : index does not have a ‘tclass’ attribute
Warning in tclass.xts(object) :
  index does not have a ‘tclass’ attribute
Warning in tzone.xts(object) : index does not have a ‘tzone’ attribute
# We want to see the managers names
colnames(managers)
 [1] "HAM1"        "HAM2"        "HAM3"        "HAM4"        "HAM5"        "HAM6"        "EDHEC.LS.EQ" "SP500.TR"   
 [9] "US.10Y.TR"   "US.3m.TR"   
# and we want to see from when to when the data is available 
first(managers)
index does not have a ‘tclass’ attributeindex does not have a ‘tzone’ attributeindex does not have a ‘tclass’ attribute
             HAM1 HAM2   HAM3   HAM4 HAM5 HAM6 EDHEC.LS.EQ SP500.TR US.10Y.TR US.3m.TR
1996-01-31 0.0074   NA 0.0349 0.0222   NA   NA          NA    0.034    0.0038  0.00456
last(managers)
index does not have a ‘tclass’ attributeindex does not have a ‘tzone’ attributeindex does not have a ‘tclass’ attribute
             HAM1    HAM2  HAM3   HAM4   HAM5   HAM6 EDHEC.LS.EQ SP500.TR US.10Y.TR US.3m.TR
2006-12-31 0.0115 -0.0062 0.011 0.0206 0.0317 0.0215      0.0153  0.01403   -0.0155  0.00441

# the Ham1-Ham6 are the asset returns we want to explain --> y in our model
asset.names <- colnames(managers[,1:6]) 

# the edhec, sp500 & US Treasury they are the explanatory ones --> x in our model
factor.names <- colnames(managers[,7:9]) 

# Typically, factor models are fit using excess returns. If the asset and factor returns are not in excess return form, "rf.name" can be specified to convert returns into excess returns. 
rf.name <- "US.3m.TR"

# Similarly, market returns can be specified via "mkt.name" to add market-timing factors to the factor model.
mkt.name <- "SP500.TR" 

Let’s take a look at the arguments for fitTsfm.

The default model fitting method is LS regression and the default variable selection method is “none” (that is, all factors are included in the model). The different model fitting options are: 1. least squares (LS), 2. discounted least squares (DLS) and 3. robust regression fitting (Robust)

And variableselection options are: 1. “stepwise”, 2. “subsets” and 3. “lars”

The default for rf.name and mkt.name are NULL. If rf.name is not specified by the user, perhaps because the data is already in excess return form, then no risk-free rate adjustment is made. Similarly, if mkt.name is not specified, market-timing factors are not added to the model. All other optional control parameters passed through the ellipsis are processed and assimilated internally by fitTsfm.control.


# The series have unequal histories in this sample and “fitTsfm“ removes asset-wise incomplete cases (asset’s return data combined with respective factors’ return data) before fitting a factor model.
args(fitTsfm)
function (asset.names, factor.names, mkt.name = NULL, rf.name = NULL, 
    data = data, fit.method = c("LS", "DLS", "Robust"), variable.selection = c("none", 
        "stepwise", "subsets", "lars"), control = fitTsfm.control(...), 
    ...) 
NULL

# Single Index Model using SP500 
fit.singleIndex <- fitTsfm(asset.names=asset.names, 
                           factor.names="SP500.TR",   #specfic factor!
                           rf.name="US.3m.TR", 
                           data=managers)
index does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attribute
# fitted object from the time-series LS regression of asset returns on estimated factors.
fit.singleIndex$asset.fit
$HAM1

Call:
lm(formula = HAM1 ~ ., data = reg.xts, model = TRUE, x = FALSE, 
    y = FALSE, qr = TRUE)

Coefficients:
(Intercept)     SP500.TR  
   0.005775     0.390071  


$HAM2

Call:
lm(formula = HAM2 ~ ., data = reg.xts, model = TRUE, x = FALSE, 
    y = FALSE, qr = TRUE)

Coefficients:
(Intercept)     SP500.TR  
   0.009093     0.338394  


$HAM3

Call:
lm(formula = HAM3 ~ ., data = reg.xts, model = TRUE, x = FALSE, 
    y = FALSE, qr = TRUE)

Coefficients:
(Intercept)     SP500.TR  
   0.006216     0.552323  


$HAM4

Call:
lm(formula = HAM4 ~ ., data = reg.xts, model = TRUE, x = FALSE, 
    y = FALSE, qr = TRUE)

Coefficients:
(Intercept)     SP500.TR  
    0.00403      0.69141  


$HAM5

Call:
lm(formula = HAM5 ~ ., data = reg.xts, model = TRUE, x = FALSE, 
    y = FALSE, qr = TRUE)

Coefficients:
(Intercept)     SP500.TR  
   0.001733     0.320833  


$HAM6

Call:
lm(formula = HAM6 ~ ., data = reg.xts, model = TRUE, x = FALSE, 
    y = FALSE, qr = TRUE)

Coefficients:
(Intercept)     SP500.TR  
   0.007837     0.323541  
# specifics values
fit.singleIndex$alpha
fit.singleIndex$beta

# Interpretation:
# if the market return rises 1%, then the return of Ham1 rises 0,39%
# R-squared is a statistical measure of how close the data are to the fitted regression line. It is also known as the coefficient of determination, or the coefficient of multiple determination for multiple regression. The definition of R-squared is fairly straight-forward; it is the percentage of the response variable variation that is explained by a linear model
# R-squared is always between 0 and 100%:
#                                           0% indicates that the model explains none of the variability of the response data around its mean.
#                                           100% indicates that the model explains all the variability of the response data around its mean


fit.singleIndex$r2
      HAM1       HAM2       HAM3       HAM4       HAM5       HAM6 
0.43386770 0.16731517 0.43409179 0.31480051 0.08286005 0.26006315 
# Interpretation:
# R-squared: 1 would be 100% - linear function matches perfectly with the data --> here we have low R-squared
# The residuals show how far the data fall from the regression line and assess how well the line describes the data.
fit.singleIndex$resid.sd
      HAM1       HAM2       HAM3       HAM4       HAM5       HAM6 
0.01934497 0.03343043 0.02737911 0.04428621 0.04413790 0.02061739 
# Interpretation:
# here we have low residuals

class(fit.singleIndex)
[1] "tsfm"
# time series factor model

names(fit.singleIndex)
 [1] "asset.fit"          "alpha"              "beta"               "r2"                 "resid.sd"          
 [6] "call"               "data"               "asset.names"        "factor.names"       "mkt.name"          
[11] "fit.method"         "variable.selection"

Overview of the single factor linear fits for the assets.


fit.singleIndex

Call:
fitTsfm(asset.names = asset.names, factor.names = "SP500.TR", 
    rf.name = "US.3m.TR", data = managers)

Model dimensions:
Factors  Assets Periods 
      1       6     132 

Regression Alphas:
                HAM1     HAM2     HAM3    HAM4     HAM5     HAM6
(Intercept) 0.005775 0.009093 0.006216 0.00403 0.001733 0.007837

Factor Betas:
           HAM1   HAM2   HAM3   HAM4   HAM5   HAM6
SP500.TR 0.3901 0.3384 0.5523 0.6914 0.3208 0.3235

R-squared values:
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
0.43387 0.16732 0.43409 0.31480 0.08286 0.26006 

Residual Volatilities:
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
0.01934 0.03343 0.02738 0.04429 0.04414 0.02062 
# Interpretation:
# How good does the single index model fits to the data?
# Ham1 equals a linear regression the most --> fits the best --> R-squared is the highest
# Ham5 does not really fit to this mode --> alfa and R-squared values

plot(fit.singleIndex, which=12, f.sub=1)

Henriksson-Merton’s - market timing models

Market timing accounts for the price movement of the general stock market relative to fixed income securities. This includes the down.market factor –> max(0, Rf-Rm) To test market timing ability, this factor can be added to the single index model as shown below. The coefficient of this down-market factor can be interpreted as the number of “free” put options on the market provided by the manager’s markettimings kills. That is, a negative value for the regression estimate would imply a negative value for market timing ability of the manager.


# Henriksson-Merton's market timing model
fit.mktTiming <- fitTsfmMT(asset.names=asset.names, 
                           mkt.name="SP500.TR", # specify which of the columns in data corresponds to the market returns using argument mkt.name.
                           rf.name="US.3m.TR", 
                           data=managers)
index does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attribute
t(fit.mktTiming$beta)
                  HAM1      HAM2        HAM3       HAM4        HAM5      HAM6
SP500.TR     0.4498075 0.1194041  0.56146555  0.9537383  0.35642547 0.2750302
down.market -0.1251174 0.4569814 -0.01914824 -0.5494516 -0.08451445 0.1060467
# Interpretation:
# Test market timing ability:
# when the value of down.market is negative, the ability of market timing of a manager is low --> not even there
# so the manager 2 has the best ability of market timing and after that manager 6 --> they have the hightes intercept (which return they will make when the market makes no return)

fit.mktTiming$r2
      HAM1       HAM2       HAM3       HAM4       HAM5       HAM6 
0.43816793 0.19598508 0.43414205 0.33395246 0.08344676 0.26314396 
# Interpretation:
# R^2 -> how good the data fits to the model. 
# all value have increased slightly

fit.mktTiming$resid.sd
      HAM1       HAM2       HAM3       HAM4       HAM5       HAM6 
0.01934591 0.03298423 0.02748381 0.04383181 0.04442091 0.02074238 
# Interpretation:
# volatility: how much it jumps around relative to its relationship to an index(sp500)
# risk: the higher the worse

###fit methods
#ls = least squares
#dls = discounted least squares (weightes least squares)
#robust = is good for data with outliers
#comparison 
fit.mktTiming

Call:
fitTsfm(asset.names = asset.names, factor.names = factor.names, 
    rf.name = NULL, data = dat.xts, fit.method = fit.method, 
    variable.selection = "none", control = control)

Model dimensions:
Factors  Assets Periods 
      2       6     132 

Regression Alphas:
                HAM1    HAM2     HAM3    HAM4     HAM5     HAM6
(Intercept) 0.007927 0.00102 0.006546 0.01348 0.003029 0.006344

Factor Betas:
               HAM1   HAM2     HAM3    HAM4     HAM5  HAM6
SP500.TR     0.4498 0.1194  0.56147  0.9537  0.35643 0.275
down.market -0.1251 0.4570 -0.01915 -0.5495 -0.08451 0.106

R-squared values:
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
0.43817 0.19599 0.43414 0.33395 0.08345 0.26314 

Residual Volatilities:
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
0.01935 0.03298 0.02748 0.04383 0.04442 0.02074 
fit.singleIndex

Call:
fitTsfm(asset.names = asset.names, factor.names = "SP500.TR", 
    rf.name = "US.3m.TR", data = managers)

Model dimensions:
Factors  Assets Periods 
      1       6     132 

Regression Alphas:
                HAM1     HAM2     HAM3    HAM4     HAM5     HAM6
(Intercept) 0.005775 0.009093 0.006216 0.00403 0.001733 0.007837

Factor Betas:
           HAM1   HAM2   HAM3   HAM4   HAM5   HAM6
SP500.TR 0.3901 0.3384 0.5523 0.6914 0.3208 0.3235

R-squared values:
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
0.43387 0.16732 0.43409 0.31480 0.08286 0.26006 

Residual Volatilities:
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
0.01934 0.03343 0.02738 0.04429 0.04414 0.02062 

Fits Model:

The different model fitting options are:

  1. (ordinary) least squares (ols / LS) –> Default mode!
  2. discounted least squares (DLS) and
  3. robust regression fitting (Robust)

Ordinary least squares (“ols”)

#  The next example performs LS regression using all 3 available factors in the dataset.
fit.ols <- fitTsfm(asset.names=asset.names, 
                   factor.names=factor.names, # all 3 available factors: the edhec, sp500 & US.10Y.TR/US Treasury
                   rf.name="US.3m.TR", 
                   data=managers) 
index does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attribute
fit.ols$beta
# Interpretation:
# now we consider all factors (explanatory factors)

# Sensitivity: 
# when the return of edhec rises 1% --> Ham2 rises 0,1547%
# when sp500 return rises 1%, Ham2 decreases by 0,195%
# when US.10Y.TR return rises 1%, Ham2 decreases by 0,0504%

fit.ols$r2
     HAM1      HAM2      HAM3      HAM4      HAM5      HAM6 
0.5005212 0.5144445 0.6569522 0.4125014 0.2322926 0.5644128 
# Interpretation:
# how good does the data fit to the model
# Ham3 fits the best with 66%

fit.ols$resid.sd
      HAM1       HAM2       HAM3       HAM4       HAM5       HAM6 
0.01888065 0.02534926 0.02161320 0.04271503 0.04093181 0.01608030 
# Interpretation:
# Volatility
# How much they jump around --> most Ham4 0.0427

Other options robust regression (“Robust”).


fit.robust <- fitTsfm(asset.names=asset.names, 
                      factor.names=factor.names, 
                      rf.name="US.3m.TR", 
                      data=managers, 
                      fit.method="Robust") # Method "Robust"!
index does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attributeLoading required package: RobStatTM
Loading required package: fit.models

Attaching package: ‘fit.models’

The following object is masked from ‘package:PortfolioAnalytics’:

    center


Attaching package: ‘RobStatTM’

The following object is masked from ‘package:robustbase’:

    BYlogreg

The following object is masked from ‘package:datasets’:

    stackloss
fit.robust$beta
# Interpretation:

fit.robust$r2
     HAM1      HAM2      HAM3      HAM4      HAM5      HAM6 
0.3786223 0.3143965 0.6166690 0.3978801 0.2879938 0.5598650 
# Interpretation:
# R-squared is now lower for each
# maybe they all had outliers

fit.robust$resid.sd
      HAM1       HAM2       HAM3       HAM4       HAM5       HAM6 
0.01871677 0.02227978 0.01591560 0.03893553 0.02970911 0.01712927 
# Interpretation:

par(mfrow=c(2,1))
plot(fit.ols, plot.single=TRUE, which=1, asset.name="HAM3")
mtext("LS", side=3)
Error in mtext("LS", side = 3) : plot.new has not been called yet
plot(fit.robust, plot.single=TRUE, which=1, asset.name="HAM3")
mtext("Robust", side=3)
Error in mtext("Robust", side = 3) : plot.new has not been called yet

par(mfrow=c(1,2)) 
plot(fit.ols, which=5, xlim=c(0,0.045), sub="LS") 

plot(fit.robust, which=5, xlim=c(0,0.045), sub="Robust")

Though the R-squared values improved by adding more factors in fit.ols (compared to the single index model)

Variable Selection

One might prefer to employ variable selection methods such as “stepwise”, “subsets” or “lars” to avoid over-fitting. The method can be selected via the variable.selection argument. The default “none”, uses all the factors and performs no variable selection:

  • Specifying “stepwise” selects traditional stepwise LS or robust regression using step or step.lmRob respectively. Starting from the given initial set of factors, factors are added (or subtracted) only if the regression fit improves.
  • Specifying “subsets” enables subsets selection using regsubsets. The best performing subset of any given size or within a range of subset sizes is chosen. Different methods such as exhaustive search (default), forward or backward stepwise, or sequential replacement can be employed.
  • Finally, “lars” corresponds to least angle regression using lars with variants “lasso” (default), “lar”, “forward.stagewise” or “stepwise”.

LARS = least angle regression


fit.lars <- fitTsfm(asset.names=asset.names, 
                    factor.names=factor.names, 
                    data=managers, 
                    rf.name="US.3m.TR", 
                    variable.selection="lars") 
index does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attribute
fit.lars

Call:
fitTsfm(asset.names = asset.names, factor.names = factor.names, 
    rf.name = "US.3m.TR", data = managers, variable.selection = "lars")

Model dimensions:
Factors  Assets Periods 
      3       6     132 

Regression Alphas:
         HAM1     HAM2     HAM3      HAM4      HAM5     HAM6
[1,] 0.005371 0.001508 -0.00124 -0.000983 -0.002843 0.004038

Factor Betas:
               HAM1    HAM2   HAM3   HAM4  HAM5    HAM6
EDHEC.LS.EQ  0.2678  1.3404 1.2509 1.1290 1.176  1.2503
SP500.TR     0.2872 -0.1051 0.1312 0.2392     . -0.1752
US.10Y.TR   -0.2302       . 0.1437      . 0.242 -0.1739

R-squared values:
  HAM1   HAM2   HAM3   HAM4   HAM5   HAM6 
0.5005 0.5064 0.6570 0.4054 0.2212 0.5644 

Residual Volatilities:
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
0.01880 0.02534 0.02152 0.04261 0.04067 0.01595 
# Interpretation:
# Subset --> the best performing subset within a range of subset sizes is chosen

fit.sub <- fitTsfm(asset.names=asset.names, 
                   factor.names=factor.names, 
                   data=managers, 
                   rf.name="US.3m.TR", 
                   variable.selection="subsets", 
                   nvmin=2, nvmax=2) 
index does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attributeindex does not have a ‘tclass’ attribute
fit.sub 

Call:
fitTsfm(asset.names = asset.names, factor.names = factor.names, 
    rf.name = "US.3m.TR", data = managers, variable.selection = "subsets", 
    nvmin = 2, nvmax = 2)

Model dimensions:
Factors  Assets Periods 
      3       6     132 

Regression Alphas:
                HAM1    HAM2      HAM3     HAM4      HAM5    HAM6
(Intercept) 0.006144 0.00063 -0.000903 -0.00183 -0.003459 0.00366

Factor Betas:
               HAM1   HAM2   HAM3   HAM4   HAM5    HAM6
EDHEC.LS.EQ       .  1.545 1.2447 1.2279 1.2944  1.2208
SP500.TR     0.3716 -0.199 0.1193 0.2847      . -0.1191
US.10Y.TR   -0.2324      .      .      . 0.3379       .

R-squared values:
  HAM1   HAM2   HAM3   HAM4   HAM5   HAM6 
0.4669 0.5137 0.6508 0.4100 0.2241 0.5422 

Residual Volatilities:
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
0.01884 0.02526 0.02171 0.04262 0.04087 0.01635 
# Here, the best subset of size 2 for each asset is chosen by specifying nvmin = nvmax = 2. Note that when nvmin < nvmax, the best subset is chosen from a range of subset sizes [nvmin, nvmax]. Default is nvmin = 1.

# Interpretation:
# we see all together
# intercepts = alpha
# where we see the indices --> betas

plot(fit.sub, which=2, f.sub=1:3)


plot(fit.lars, which=2, f.sub=1:3)

Big Interpretation

Comparing the coefficients and R-squared values from the two models, we find that the method that uses more factors for an asset have higher R-squared values as expected. However, when both “lars” and “subsets” chose the same number of factors, “lars” fits have a slightly higher R-squared values.

S3 generic methods

Many useful generic accessor functions are available for “tsfm” fit objects:

  • coef() returns a matrix of estimated model coefficients including the intercept.
  • fitted() returns an xts data object of the component of asset returns explained by the factor model.
  • residuals() returns an xts data object with the component of asset returns not explained by the factor model.
  • predict() uses the fitted factor model to estimate asset returns given a set of new or simulated factor return data.
  • summary() prints standard errors and t-statistics for all estimated coefficients in addition to R-squared values and residual volatilities.

Argument se.type, one of “Default”, “HC” or “HAC”, allows for heteroskedasticity and auto-correlation consistent estimates and standard errors whenever possible. A “summary.tsfm” object is returned which contains a list of summary objects returned by “lm”, “lm.Rob” or “lars” for each asset fit.


methods(class="tsfm")
 [1] coef          fitted        fmCov         fmEsDecomp    fmSdDecomp    fmVaRDecomp   plot          portEsDecomp 
 [9] portSdDecomp  portVaRDecomp portVolDecomp predict       print         repRisk       residuals     riskDecomp   
[17] summary      
see '?methods' for accessing help and source code

All estimated coefficients from the LS fit using all 3 factors


coef(fit.ols)
NA

Compare returns data with fitted and residual values for HAM1 from fit.lars


HAM1.ts <- merge(fit.lars$data[,1], 
                 fitted(fit.lars)[,1], 
                 residuals(fit.lars)[,1]) 

colnames(HAM1.ts) <- c("HAM1.return","HAM1.fitted","HAM1.residual") 

tail(HAM1.ts)
           HAM1.return HAM1.fitted HAM1.residual
2006-07-31    -0.01863 0.001310394  -0.019940394
2006-08-31     0.01169 0.008784678   0.002905322
2006-09-30     0.00224 0.008701977  -0.006461977
2006-10-31     0.03889 0.017346504   0.021543496
2006-11-30     0.00740 0.011519868  -0.004119868
2006-12-31     0.00709 0.015633989  -0.008543989
# Interpretation:
# fitted --> the returns which can be explained through the model
# residual --> the returns which cannot be explained through the model

Summary for fit.sub computing HAC standard erros


summary(fit.sub, se.type="HAC")

Call:
fitTsfm(asset.names = asset.names, factor.names = factor.names, 
    rf.name = "US.3m.TR", data = managers, variable.selection = "subsets", 
    nvmin = 2, nvmax = 2)

Factor Model Coefficients:

Asset1: HAM1
(HAC Standard Errors & T-stats)

            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.00614    0.00181    3.40   0.0009 ***
SP500.TR     0.37163    0.04930    7.54  7.4e-12 ***
US.10Y.TR   -0.23242    0.07091   -3.28   0.0013 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-squared: 0.467, Residual Volatility: 0.0188

Asset2: HAM2
(HAC Standard Errors & T-stats)

            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.00063    0.00239    0.26    0.792    
EDHEC.LS.EQ  1.54468    0.24583    6.28  5.9e-09 ***
SP500.TR    -0.19897    0.10595   -1.88    0.063 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-squared: 0.514, Residual Volatility: 0.0253

Asset3: HAM3
(HAC Standard Errors & T-stats)

             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.000903   0.001871   -0.48  0.63029    
EDHEC.LS.EQ  1.244687   0.328379    3.79  0.00024 ***
SP500.TR     0.119303   0.124063    0.96  0.33822    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-squared: 0.651, Residual Volatility: 0.0217

Asset4: HAM4
(HAC Standard Errors & T-stats)

            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.00183    0.00428   -0.43  0.66977    
EDHEC.LS.EQ  1.22790    0.34069    3.60  0.00046 ***
SP500.TR     0.28467    0.12115    2.35  0.02046 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-squared: 0.41, Residual Volatility: 0.0426

Asset5: HAM5
(HAC Standard Errors & T-stats)

            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.00346    0.00396   -0.87     0.38    
EDHEC.LS.EQ  1.29442    0.28326    4.57  1.9e-05 ***
US.10Y.TR    0.33791    0.21106    1.60     0.11    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-squared: 0.224, Residual Volatility: 0.0409

Asset6: HAM6
(HAC Standard Errors & T-stats)

            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.00366    0.00286    1.28     0.20    
EDHEC.LS.EQ  1.22084    0.21548    5.67  4.2e-07 ***
SP500.TR    -0.11910    0.10905   -1.09     0.28    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-squared: 0.542, Residual Volatility: 0.0163

Factor Model Covariance & Risk Decomposition

Factor model covariance

# the factor model covariance from a fitted factor model.
fmCov(fit.sub)
         HAM1     HAM2     HAM3     HAM4     HAM5     HAM6
HAM1 0.000661 0.000257 0.000411 0.000527 0.000286 0.000231
HAM2 0.000257 0.001297 0.000710 0.000807 0.000631 0.000545
HAM3 0.000411 0.000710 0.001334 0.001024 0.000732 0.000601
HAM4 0.000527 0.000807 0.001024 0.003051 0.000855 0.000689
HAM5 0.000286 0.000631 0.000732 0.000855 0.002348 0.000529
HAM6 0.000231 0.000545 0.000601 0.000689 0.000529 0.000720
# factor model return correlation plot
plot(fit.sub, which=8)

Standard deviation decomposition

# fmSdDecomp performs a decomposition for all assets in the given factor model fit object
decomp <- fmSdDecomp(fit.sub)
names(decomp)
[1] "Sd.fm" "mSd"   "cSd"   "pcSd" 
# All Information together
decomp
$Sd.fm
  HAM1   HAM2   HAM3   HAM4   HAM5   HAM6 
0.0257 0.0360 0.0365 0.0552 0.0485 0.0268 

$mSd
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1      0.0101   0.0284 -0.005874     0.733
HAM2      0.0141   0.0178 -0.002272     0.701
HAM3      0.0162   0.0284 -0.002941     0.594
HAM4      0.0126   0.0242 -0.002367     0.772
HAM5      0.0106   0.0165  0.000953     0.843
HAM6      0.0159   0.0215 -0.002621     0.609

$cSd
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1      0.0000  0.01054  0.001365   0.01381
HAM2      0.0218 -0.00354  0.000000   0.01772
HAM3      0.0202  0.00339  0.000000   0.01291
HAM4      0.0154  0.00689  0.000000   0.03289
HAM5      0.0137  0.00000  0.000322   0.03447
HAM6      0.0194 -0.00256  0.000000   0.00996

$pcSd
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1         0.0    41.00     5.309      53.7
HAM2        60.6    -9.82     0.000      49.2
HAM3        55.4     9.29     0.000      35.3
HAM4        28.0    12.48     0.000      59.6
HAM5        28.2     0.00     0.664      71.1
HAM6        72.4    -9.54     0.000      37.1
# get:
decomp$Sd.fm
  HAM1   HAM2   HAM3   HAM4   HAM5   HAM6 
0.0257 0.0360 0.0365 0.0552 0.0485 0.0268 
#     the factor model standard deviation for all assets
decomp$cSd
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1      0.0000  0.01054  0.001365   0.01381
HAM2      0.0218 -0.00354  0.000000   0.01772
HAM3      0.0202  0.00339  0.000000   0.01291
HAM4      0.0154  0.00689  0.000000   0.03289
HAM5      0.0137  0.00000  0.000322   0.03447
HAM6      0.0194 -0.00256  0.000000   0.00996
#     the component contributions to Sd
decomp$mSd
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1      0.0101   0.0284 -0.005874     0.733
HAM2      0.0141   0.0178 -0.002272     0.701
HAM3      0.0162   0.0284 -0.002941     0.594
HAM4      0.0126   0.0242 -0.002367     0.772
HAM5      0.0106   0.0165  0.000953     0.843
HAM6      0.0159   0.0215 -0.002621     0.609
#     the marginal factor contributions to Sd
decomp$pcSd
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1         0.0    41.00     5.309      53.7
HAM2        60.6    -9.82     0.000      49.2
HAM3        55.4     9.29     0.000      35.3
HAM4        28.0    12.48     0.000      59.6
HAM5        28.2     0.00     0.664      71.1
HAM6        72.4    -9.54     0.000      37.1
#     the percentage component contributions to Sd

# plot the percentage component contributions to Sd
plot(fit.sub, which=9, f.sub=1:3)

Value-at-Risk decomposition

VaR = The value at risk for a given probability level indicates the amount of loss that will not be exceeded within a given period of time with this probability


decomp1 <- fmVaRDecomp(fit.sub)
names(decomp1)
[1] "VaR.fm"     "n.exceed"   "idx.exceed" "mVaR"       "cVaR"       "pcVaR"     
# All Information together
decomp1
$VaR.fm
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
-0.0290 -0.0335 -0.0440 -0.0833 -0.0752 -0.0357 

$n.exceed
HAM1 HAM2 HAM3 HAM4 HAM5 HAM6 
   7    7    7    7    4    4 

$idx.exceed
$idx.exceed$HAM1
[1]  32  69  79  81  84  85 125

$idx.exceed$HAM2
[1]  51  57  58  61  74  78 122

$idx.exceed$HAM3
[1] 32 38 55 57 78 81 84

$idx.exceed$HAM4
[1]  32  58  68  69  79  81 100

$idx.exceed$HAM5
[1] 58 61 68 70

$idx.exceed$HAM6
[1]  79 103 112 118


$mVaR
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1    -0.01169  -0.0289  0.005761    -0.899
HAM2    -0.00997  -0.0206  0.005903    -0.880
HAM3    -0.01871  -0.0540  0.008118    -0.656
HAM4    -0.01368  -0.0353 -0.000279    -1.326
HAM5    -0.01020  -0.0291 -0.000389    -1.513
HAM6    -0.01705  -0.0273  0.009859    -1.108

$cVaR
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1      0.0000 -0.01075 -0.001339   -0.0169
HAM2     -0.0154  0.00410  0.000000   -0.0222
HAM3     -0.0233 -0.00645  0.000000   -0.0143
HAM4     -0.0168 -0.01005  0.000000   -0.0565
HAM5     -0.0132  0.00000 -0.000131   -0.0618
HAM6     -0.0208  0.00326  0.000000   -0.0181

$pcVaR
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1         0.0    37.01     4.611      58.4
HAM2        45.9   -12.22     0.000      66.3
HAM3        52.9    14.66     0.000      32.4
HAM4        20.1    12.06     0.000      67.8
HAM5        17.6     0.00     0.175      82.3
HAM6        58.3    -9.13     0.000      50.8
# get the factor model value-at-risk for all assets
decomp1$VaR.fm
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
-0.0290 -0.0335 -0.0440 -0.0833 -0.0752 -0.0357 
# get the percentage component contributions to VaR
decomp1$pcVaR
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1         0.0    37.01     4.611      58.4
HAM2        45.9   -12.22     0.000      66.3
HAM3        52.9    14.66     0.000      32.4
HAM4        20.1    12.06     0.000      67.8
HAM5        17.6     0.00     0.175      82.3
HAM6        58.3    -9.13     0.000      50.8
# plot the percentage component contributions to VaR
plot(fit.sub, which=11, f.sub=1:3)

Expected Shortfall decomposition

The term risk measure is a collective term for statistical measures that can be used to quantitatively describe the uncertainty of an event. VaR is defined as the amount of loss that will not be exceeded in a given period of time with a specified probability p (“confidence level” α = 1 - p).


decomp2 <- fmEsDecomp(fit.sub, method="historical")
names(decomp2)
[1] "ES.fm" "mES"   "cES"   "pcES" 
# get the factor model expected shortfall for all assets
decomp2$ES.fm
   HAM1    HAM2    HAM3    HAM4    HAM5    HAM6 
-0.0538 -0.0370 -0.0586 -0.1153 -0.1067 -0.0411 
# get the component contributions to Sd
decomp2$cES
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1     0.00000 -0.02592  -0.00441   -0.0235
HAM2    -0.01232  0.00111   0.00000   -0.0258
HAM3    -0.02715 -0.00873   0.00000   -0.0227
HAM4    -0.03576 -0.02132   0.00000   -0.0582
HAM5    -0.00309  0.00000   0.00302   -0.1067
HAM6    -0.02737  0.00422   0.00000   -0.0180
# get the marginal factor contributions to ES
decomp2$mES
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1    -0.02593 -0.06975   0.01898     -1.25
HAM2    -0.00798 -0.00559   0.00658     -1.02
HAM3    -0.02181 -0.07315   0.01157     -1.05
HAM4    -0.02912 -0.07488   0.01364     -1.37
HAM5    -0.00239 -0.00771   0.00894     -2.61
HAM6    -0.02242 -0.03544   0.01181     -1.10
# get the percentage component contributions to ES
decomp2$pcES
     EDHEC.LS.EQ SP500.TR US.10Y.TR Residuals
HAM1         0.0     48.1      8.19      43.7
HAM2        33.3     -3.0      0.00      69.7
HAM3        46.3     14.9      0.00      38.8
HAM4        31.0     18.5      0.00      50.5
HAM5         2.9      0.0     -2.83      99.9
HAM6        66.6    -10.3      0.00      43.7
# plot the percentage component contributions to ES
plot(fit.sub, which=10, f.sub=1:3)

Plot

Group Plots


plot(fit.sub, which=6)

# Make a plot selection (1-12 or 0 to exit)

Individual Plots


plot(fit.sub, plot.single=TRUE, asset.name="HAM1", which=10)


plot(fit.sub, plot.single=TRUE, asset.name="HAM1", which=14)
grid()


plot(fit.sub, plot.single=TRUE, asset.name="HAM1", which=11)


plot(fit.sub, plot.single=TRUE, asset.name="HAM1", which=12)

Exercise 5: Fundamental Factor Models

Follow the file ffmVignette.pdf and interpret your results.

Theorie

The general mathematical form of equity fundamental factor model (FFM) implemented in factorAnalytics is rt = αt· 1 + Bt−1ft + εt, t = 1, 2, · · · , T (1)

where: - equity returns vector rt and the vectors 1 and - εt are N ×1 vectors, - Bt−1 is an N ×K exposures (risk factors) matrix, and - ft is a K × 1 vector of random factor returns. - It is assumed that the εt hav zero mean with diagonal covariance matrix Dt = diag(σ2t,1, σ2t,2, · · · , σ2t,N), and are uncorrelated with the ft


# factorAnalytics
# The following U.S. stock returns and data sets are included in factorAnalytics for now:
#
# 1) factorDataSetDjia: 
#                       - Monthly returns of 30 stocks in the DJIA from January 2000 to March 2013 = Dow Jones Industrial Average 
#                       - with 5 corresponding style factors:
#                           - MKTCAP  (Market Capitalization)
#                           - ENTVAL  (Entitled Value)
#                           - P2B     () Platform to Business
#                           - EV2S    ()
#                           - SIZE    ()
#                       - and a sector factor with 9 sectors:
#                           - ENERGY  (Energy), 
#                           - COSTAP  (Consumer Staples), 
#                           - INDUST  (Industry), 
#                           - MATRLS  (Materials), 
#                           - FINS    (Financials), 
#                           - INFOTK  (Information Technology), 
#                           - HEALTH  (Healthcare)
#                           - CODISC  (Consumer Discretionary), 
#                           - TELCOM  (Telecommunications)] 
# 
#
# 2) factorDataSetDjia5Yrs: 
#                       - A five-year segment of factorDataSetDjia from January 2008 to December 2012.
#
#
# 3) wtsDjiaGmvLo: 
#                       - Weight vector of dimension 30 containing the weights of a long-only 
#                         global minimum variance (GMV) portfolio for the 30 stocks in the factorDataSetDjia5Yrs data set.
#                       - The weight vector was obtained using PortfolioAnaltyics with the usual sample covariance matrix 
#                         based on the 5 years of returns in factorDataSetDjia5Yrs.


data("factorDataSetDjia5Yrs") 

dataDjia5Yr = factorDataSetDjia5Yrs 

head(dataDjia5Yr,5) 

1. Fitting a Fundamental Factor Model - FFM

A FFM is generally fit by a two-step method: 1) using least squares or robust regression methods in the first step, 2) and using weighted least squares or weighted robust regression in the second step where the weights are computed in the first step.

# The Fundamental-Factor-Model-Function: fitFfm

fitDjia5Yr = fitFfm(dataDjia5Yr, addIntercept = T, 
                    asset.var = "TICKER",                                 # asset.var = name of variable for asset names 
                    ret.var = "RETURN",                                   # ret.var = name of variable for asset returns 
                    date.var = "DATE",                                    # date.var = name of variable containing the dates 
                    exposure.vars = c("SECTOR","SIZE", "P2B", "EV2S"),    # exposrue.var = variables containing the fundamental factor exposures 
                    z.score = "crossSection")                             # z.score has to be one of "none", "crossSection", or "timeSeries" 

names(fitDjia5Yr) 
 [1] "factor.fit"      "beta"            "factor.returns"  "residuals"       "r2"              "factor.cov"     
 [7] "g.cov"           "resid.cov"       "return.cov"      "restriction.mat" "resid.var"       "call"           
[13] "time.periods"    "data"            "date.var"        "ret.var"         "asset.var"       "exposure.vars"  
[19] "weight.var"      "fit.method"      "asset.names"     "factor.names"    "activeWeights"   "activeReturns"  
[25] "IR"             

1.1. Model Fit R-Squared Values

One of the most basic model fit statistics is the R-squared, and you can assess the goodness of your FFM fits by using the function ffmRsq to make a plot of the time series of R-squared values for each of the 60 fits over the five-year window. This function computes and plots the time series of ordinary R-squared by default, but it can do that for the adjusted R-squared, or both.


# Fit R-Squared Values

fmRsq(fitDjia5Yr,
      rsq = T,              # logical; if TRUE, Factor Model R-squared values are computed for the portfolio. Default is TRUE.
      rsqAdj = T,           # logical; if TRUE, Adjusted R-squared values are computed for the portfolio. Default is FALSE.
      plt.type = 2,         # 1 indicates barplot, 2 indicates time series xy plot. Default is 2.
      isPrint = F, 
      lwd = 0.7, 
      stripText.cex = 0.8, 
      axis.cex = 0.8) 
    Mean R-Squared Mean Adj R-Squared 
              0.78               0.54 

 
# Interpretation:
# 1) Upper Plot: Mean R-Squared across periods = 0.78 (Output of the Junk) 
#    -> problem, R-Squared increases everytime an independant variable is added, which means the more independant variables the higher the R-Squared. 
# 2) Mean adjusted R-Squared = 0.54 (Output of the Junk) 
#    -> as soon as we take the problem with R-Squared into account and use the adjusted mean, we see that the value drops from 78% to 54% and that there 
#       are even negative single values. 
 

1.2 Model Fit Variance Inflation Factors - (VIF’s)

When your model includes continuous style factor variables the function ffmRsq also allows you to compute and display the time series of variance inflation factors (VIF’s). These can help you determine whether or not there are any regression collinearity problems.


# the time series of mean variance inflation factors (VIF’s) 
vif(fitDjia5Yr, 
    isPlot = T, 
    isPrint = F, 
    lwd = 0.7, 
    stripText.cex = 0.8, 
    axis.cex = 0.8) 
$Mean.VIF
SIZE  P2B EV2S 
1.14 1.09 1.15 

 
#Multikollinearität ist ein Problem der Regressionsanalyse und liegt vor, wenn zwei oder mehr erklärende Variablen eine sehr starke Korrelation miteinander haben. Zum einen wird mit zunehmender Multikollinearität das Verfahren zur Schätzung der Regressionskoeffizienten instabil und Aussagen zur Schätzung der Regressionskoeffizienten zunehmend ungenau. Zum anderen ist die Modellinterpretation nicht mehr eindeutig. Das klassische Symptom von starker Multikollinearität ist ein hohes Bestimmtheitsmaß einhergehend mit niedrigen t-Werten für die einzelnen Regressionsparameter.

1.3 Model Fit t-Statistics

Plots of the time series of t-statistics for the factors in an FFM fitted model, with horizontal dashed lines provided to judge whether or not a factor is significant at the 5% level, may be obtained with the function ffmTstats.


# The time series of t-statistics for the factors (5% significant level)
fmTstats(fitDjia5Yr, 
         whichPlot = "tStats", 
         color = "blue", 
         lwd = 0.7, 
         layout = c(3, 4), 
         stripText.cex = 0.8, 
         axis.cex = 0.8) 


# Interpretation:
# fmTstats can also compute the number of significant t-statistics:
#         the number of positive, 
#         negative and 
#         total significant t-statistics 

fmTstats(fitDjia5Yr, 
         whichPlot = "significantTstatsV", 
         color = "blue", 
         stripText.cex = 0.8, 
         axis.cex = 0.8, 
         layout = c(3, 4)) 


# Interpretation: 3 style factors + market  + 8 sectors

# red lines shows critical values t statistic; everything larger in (abolute value)  then critical value is signnificant 

# result of colinearity -> not many significant parameters

# see below: relativley low amount of significant parameters (execept for market)

2. Risk and Performance Report

The factorAnalytics package contains the following risk and performance reporting functions: 1) repExposures 2) repReturn 3) repRisk

We illustrate the use of each of these in turn using “fitDjia5Yr” and the corresponding global minimum variance long-only portfolio weights object “wtsDjiaGmvLo”


# load the long-only global minimum variance portfolio weights vector 
data(wtsDjiaGmvLo) 

# and give it the shorter name wtsDjia 
wtsDjia = wtsDjiaGmvLo 

2.1) repExposure

The portfolio exposure to a given risk factor is the inner (dot) product of the portfolio weight vector with the column of the exposures matrix Bt−1 corresponding to the given factor. The style factors vary over time, but the sector factors are fixed and each sector is represented by a column of zero’s and ones. Thus the portfolio exposure to style factors will vary over time and thus have a distribution with a mean and volatility. On the other hand the portfolio exposure to sector factors will have a fixed value depending on the portfolio weights and number of firms in a given sector.


# compute volatilities of the style factors and sector factors 
repExposures(fitDjia5Yr,
             wtsDjia,
             isPlot = F,
             digits = 1, 
             stripText.cex = 0.8,
             axis.cex = 0.8) 
$Style.Exposures
      Mean Volatility
SIZE  89.6        4.6
P2B   25.2       20.0
EV2S -31.5        6.8

$Sec.Exposures
# Interpretation:
# Exposure generally refers to the fact of being exposed to a risk.
# Just three factors have a volatility:
# 1) Style factor P2B: with 20.0. 
# 2) Style factor EV2S: with -31.5
# 3) Stlye factor Size: with 4.6

# plot the volatilities of the style factors and sector factors 
repExposures(fitDjia5Yr, 
             wtsDjia, 
             isPrint = F, 
             isPlot = T, 
             which = 3, 
             add.grid = F, 
             zeroLine = T, 
             color = "Blue") 


# plot the time series of the style factor exposures 
repExposures(fitDjia5Yr, 
             wtsDjia, 
             isPrint = F, 
             isPlot = T, 
             which = 1, 
             add.grid = F, 
             zeroLine = T, 
             color = "Blue", 
             stripText.cex = 0.8,
             axis.cex = 0.8) 


#display boxplots of those exposures 
repExposures(fitDjia5Yr,
             wtsDjia,
             isPrint = FALSE, 
             isPlot = TRUE,
             which = 2,
             notch = F,
             layout = c(3,3)) 

2.2) repReturn

The function repReteurn provides you with the following choices of graphical reports, the results of which will also be printed because of the default printing option isPrint = T: 1. Time Series plot of portfolio returns decomposition 2. Time Series plot of portfolio style factors returns 3. Time Series plot of portfolio sector returns 4. Boxplot of Portfolio Returns Components.

# caluclate mean and volatility of the various portfolio return components with the help of repReturn 
repReturn(fitDjia5Yr,
          wtsDjia,
          isPlot = FALSE,
          digits = 2) 
          Mean Volatility
PortRet   0.85       3.78
ResidRet  0.10       1.46
FacRet    0.76       3.30
Market    0.48       5.78
SIZE      0.16       2.49
P2B       0.14       0.51
EV2S      0.06       0.60
COSTAP    0.01       1.66
ENERGY   -0.03       0.97
FINS      0.00       0.00
HEALTH    0.02       0.46
INDUST    0.00       0.00
INFOTK   -0.10       0.73
MATRLS    0.00       0.00
TELCOM    0.01       0.37
# Interpretation: 

# Plot portfolio returns decomposition 
repReturn(fitDjia5Yr,
          wtsDjia,
          isPrint = FALSE,
          isPlot = TRUE, 
          which = 1,
          add.grid = TRUE,
          scaleType = "same", 
          color = "Blue",
          stripText.cex = 0.8,
          axis.cex = 0.8) 


# Interpretation: 

# Plot portfolio styles factor return 
repReturn(fitDjia5Yr, 
          wtsDjia, 
          isPrint = FALSE,
          isPlot = TRUE, 
          which = 2,
          add.grid = TRUE,
          zeroLine = T,
          color = "Blue", 
          scaleType = "same",
          stripText.cex = 0.8,
          axis.cex = 0.8) 


# Interpretation: 

# Plot portfolio sectors return 
repReturn(fitDjia5Yr,
          wtsDjia,
          isPrint = FALSE,
          isPlot = TRUE, 
          which = 3,
          add.grid = TRUE,
          zeroLine = T,
          color = "Blue", 
          scaleType = "same",
          stripText.cex = 0.8,
          axis.cex = 0.8) 


# Interpretation: 

# Boxplot of Portfolio Returns Components 
repReturn(fitDjia5Yr,
          wtsDjia,
          isPrint = FALSE,
          isPlot = TRUE,
          which = 4) 


# Interpretation: 

2.3) repRisk

The function repRisk allows one to compute and display (graphically and in tabular form) factor decompositions of risk for a portfolio and for each of the assets used to fit a fundamental factor model with fitFfm. The risk measure can be chosen as: - standard deviation/volatility (SD) - expected shortfall (ES) - or value-at-risk (VaR)

and the factor risk decomposition can be chosen as: - factor percent contribution to risk (FPCR) - factor contribution to risk (FCR) - or factor marginal contribution to risk (FMCR).

# standard deviation/volatility (SD)
# factor percent contribution to risk - (FPCR)

# First we compute an FPCR decomposition of the portfolio and individual assets using Sd as the risk measure, and provide both Lattice visualization and tabular displays. For the Lattice display the argument sliceby = “factor” specifies that the panel conditioning is by risk factor and the choice layout = c(5,1) results in a single row with five panels. We used nrowPrint = 10 to shorten the printed output from one row for the portfolio factor risk decomposition and 22 rows (we are only using 22 of the DJIA stocks at the moment) for the stock factor risk decompositions to one row for the portfolio and 9 rows for the assets. 
 
fitDjia5YrIntStyle = fitFfm(data = dataDjia5Yr,
                            exposure.vars = c("SIZE", "P2B", "EV2S"), 
                            date.var = "DATE", 
                            ret.var = "RETURN", 
                            asset.var = "TICKER", 
                            fit.method = "WLS", 
                            z.score = "crossSection", 
                            addIntercept = T) 
 
repRisk(fitDjia5YrIntStyle, 
        wtsDjia, 
        risk = "Sd", 
        decomp = "FPCR", 
        nrowPrint = 10, 
        sliceby = "factor", 
        isPrint = T, 
        isPlot = T, 
        layout = c(5, 1), 
        stripText.cex = 0.8, 
        axis.cex = 0.8) 
$SdFPCR
          Alpha  SIZE  P2B EV2S Resid
Portfolio 102.0 -18.3 -0.4 -1.3  18.0
AA         28.9  45.2  4.0 -2.2  24.0
BA         54.3  16.7  8.7  4.3  16.0
BAC        15.1  -0.8  2.1 11.2  72.3
CAT        37.0  12.3 -0.2 -1.4  52.4
CVX        64.1 -12.8  4.4  4.9  39.4
DD         53.1  28.0 -1.8 -1.6  22.3
GE         34.6  -8.7  2.0 17.4  54.6
HPQ        37.1  26.4  3.4 -0.2  33.3
IBM        22.3  -0.6 26.0  0.1  52.3

# Interpretation: 
# expected shortfall (ES)
# factor percent contribution to risk - (FPCR)

# Now we use expected shortfall (ES) to do an FPCR decomposition and provide only the Lattice 
repRisk(fitDjia5YrIntStyle, 
        wtsDjia, 
        risk = "ES", 
        decomp = "FPCR", 
        nrowPrint = 10, 
        sliceby = "factor", 
        isPrint = F, 
        isPlot = T, 
        layout = c(5, 1),
        stripText.cex = 0.8, 
        axis.cex = 0.8) 
NULL

# Interpretation: 
# How many percent of standard deviation are determinded by systemic risk (size, p2b, ev2s) and idiosyncratic risk (Resid)

# expected shortfall (ES)
# factor contribution to risk (FCR) 

# Now we use expected shortfall (VaR) to do the FCR decomposition 

repRisk(fitDjia5YrIntStyle, 
        wtsDjia, 
        risk = "VaR",
        decomp = "FPCR", 
        nrowPrint = 10,
        sliceby = "factor",
        isPrint = F, 
        isPlot = T,
        layout = c(5, 1),
        stripText.cex = 0.8, 
        axis.cex = 0.8) 
NULL

# Interpretation: 

# compare the factor risk decompositions of a portfolio using all three risk measures, skipping the risk decomposition of the assets 
repRisk(fitDjia5YrIntStyle, 
        wtsDjia, 
        risk = c("Sd", "ES", "VaR"),
        decomp = "FPCR",
        sliceby = "factor", 
        isPrint = T,
        isPlot = TRUE,
        layout = c(5, 1),
        portfolio.only = T, 
        stripText.cex = 0.8,
        axis.cex = 0.8) 
the condition has length > 1 and only the first element will be used
$`Portfolio FPCR Non-Parametric`
    Total Alpha  SIZE   P2B EV2S Resid
Sd    100   102 -18.3  -0.4 -1.3  18.0
ES    100   180 -64.2 -10.3 -6.7   0.9
VaR   100   189 -76.6  -7.8 -3.0  -2.1

# Interpretation: 

3. Factor Model Monte Carlo

The use of factor model Monte Carlo (FMMC) for a fundamental factor model results in a simulated set of asset returns based on a resampling of factor returns and a resampling or simulation of residual returns of the fitted model, using the exposures matrix from the last time period used in fitting the model.
The factorAnalytics function fmmcSemiParametric implements the above FMMC method based on function araguments that are the result of first fitting fundamental factor model to the data with fitFfm, combined with function arguments based on user options concerning the type of FMMC. We will illustrate the use of fmmcSemiParametric on the DJIA five-year monthly data set factorDataSetDjia5Yrs.


# But first we take a look at the arguments of the function 
args(fmmcSemiParam) 
function (B = 1000, factor.ret, beta, alpha, resid.par, resid.dist = c("normal", 
    "Cornish-Fisher", "skew-t", "empirical"), boot.method = c("random", 
    "block"), seed = 123) 
NULL

Aguments: - B is the number of bootstrap samples. - factor.ret is the set of factor returns estimates returned by the use of fitFfm - beta is exposures matrix for the final period returned by fitFfm - alpha is a fixed vector of intercept values that if ommited are assumed to be zero.

Our example below uses the default values B = 1000, boot.method = “random” (means simple bootstrap), seed = 123 (for reproducibility of the example).

We use two choices of resid.dist, first we use resid.dist = “empirical” which corresponds to 2-(a) above and then we use resid.dist = “normal”. The user must provide appropriate values for resid.par that depend on the the choice for resid.dist. For the choice resid.dist = “empirical” the resid.par must be the N × T dimensional xts time series in the $residuals component of the model fit, and for the choice resid.dist = “normal” the resid.par must be an N × 2 matrix with the first column being estimates of the means of the residuals for each of the N assets and the second column being estimates of the standard deviations of the residuals for each of the assets

# In order to use fmmcSemiParam for the DJIA data we first fit a fundamental factor model (without alpha or market term) to the factorDataSetDjia5Yrs data 
data("factorDataSetDjia5Yrs") 
N = 30 

exposure.vars <- c("P2B", "MKTCAP", "SECTOR") 

fit.ffm = fitFfm(data = factorDataSetDjia5Yrs,
                 asset.var = "TICKER", 
                 ret.var = "RETURN",
                 date.var = "DATE",
                 exposure.vars = exposure.vars) 

# Next we use fmmcSemiParam to create simulated values of the asset returns based on the use of bootstrapped factor returns and bootstrapped (empirical) residuals: 
resid.par = fit.ffm$residuals 

fmmcDat = fmmcSemiParam(B = 1000,
                        factor.ret = fit.ffm$factor.returns, 
                        beta = fit.ffm$beta, 
                        resid.par = resid.par,
                        boot.method = "random", 
                        resid.dist = "empirical") 
names(fmmcDat) 
[1] "sim.fund.ret"    "boot.factor.ret" "sim.resid"      

“sim.fund.ret” = a B × N matrix of simulated asset returns, “boot.factor.ret” = a B × K matrix of simulated factor returns, “sim.resid” = a B × N matrix of simulated residuals


# Now let’s verify that the that returns of the 30 DJIA stocks over the five-year period are well represented by the set of 500 simulated sets of 30 returns in fmmcDat$sim.fund.return with respect to returns means and standard deviations. In order to do this we first extract the multivariate time series of returns of those stocks from the data frame factorDataSetDjia5Yrs 
data = factorDataSetDjia5Yrs 

djiaDat = tapply(data$RETURN,
                 list(data$DATE, data$TICKER),
                 I) 

djiaRet = xts(djiaDat,
              as.yearmon(rownames(djiaDat))) 

# Now we compare the simulated returns means with the observed returns means for the first 10 DJIA stocks 
round(apply(djiaRet, 2, mean)[1:10], 3) 
    AA     BA    BAC    CAT    CVX     DD     GE    HPQ    IBM   INTC 
-0.012  0.004  0.000  0.014  0.007  0.008  0.000 -0.016  0.013  0.002 
round(apply(fmmcDat$sim.fund.ret, 2, mean)[1:10], 3) 
    AA     BA    BAC    CAT    CVX     DD     GE    HPQ    IBM   INTC 
-0.010  0.011 -0.004  0.012  0.006  0.004 -0.003 -0.011  0.012  0.003 

#same thing for returns standard deviations 
round(apply(djiaRet, 2, sd)[1:10], 3) 
   AA    BA   BAC   CAT   CVX    DD    GE   HPQ   IBM  INTC 
0.137 0.089 0.197 0.126 0.064 0.093 0.109 0.090 0.056 0.081 
round(apply(fmmcDat$sim.fund.ret, 2, sd)[1:10], 3) 
   AA    BA   BAC   CAT   CVX    DD    GE   HPQ   IBM  INTC 
0.141 0.080 0.187 0.125 0.057 0.093 0.105 0.094 0.056 0.079 

The use of fmmcSemiParam with bootstrapped residuals as well as bootstrapped factor returns is attractive because it is simple and because in addition to making no distributional assumptions about the factor returns it makes no assumptions about the distributions of the residuals.

By way of contrast let’s see what happens if we assume the residuals associated with the 30 DJIA fitted fundamental factor model returns have normal distributions and fit them using the sample means and standard deviations of the residuals.


# First we use fmmcSemiParam with default choice resid.dist = “normal” and with resid.par a matrix with first column the sample mean of the residuals and second column the standard deviation of teh residuals 
 
resid.mean = apply(B = 1000,
                   coredata(fit.ffm$residuals),
                   2, 
                   mean,
                   na.rm = T) 

resid.sd = matrix(sqrt(fit.ffm$resid.var)) 
 
resid.par = cbind(resid.mean, resid.sd) 

fmmcDatNormal = fmmcSemiParam(factor.ret = fit.ffm$factor.returns, 
                             beta = fit.ffm$beta, 
                             resid.par = resid.par,
                             boot.method = "random") 

#Then we compare the means of the simulated asset returns with those of the actual returns 
round(apply(djiaRet, 2, mean)[1:10], 3) 
    AA     BA    BAC    CAT    CVX     DD     GE    HPQ    IBM   INTC 
-0.012  0.004  0.000  0.014  0.007  0.008  0.000 -0.016  0.013  0.002 
round(apply(fmmcDatNormal$sim.fund.ret, 2, mean)[1:10], 3) 
    AA     BA    BAC    CAT    CVX     DD     GE    HPQ    IBM   INTC 
-0.013  0.010 -0.001  0.010  0.006  0.006 -0.004 -0.014  0.013  0.001 

#Same with the standard deviation 
round(apply(djiaRet, 2, sd)[1:10], 3) 
   AA    BA   BAC   CAT   CVX    DD    GE   HPQ   IBM  INTC 
0.137 0.089 0.197 0.126 0.064 0.093 0.109 0.090 0.056 0.081 
round(apply(fmmcDatNormal$sim.fund.ret, 2, sd)[1:10], 3)
   AA    BA   BAC   CAT   CVX    DD    GE   HPQ   IBM  INTC 
0.121 0.081 0.155 0.099 0.060 0.114 0.089 0.089 0.061 0.082 

Once again the mean values agree quite well, but we see that the simulated returns based on the assumption of normally distributed returns have volatilities that under-estimate the actual returns volatilities for eight of the first 10 stocks. However, comparison of the volatilities for all 30 stocks reveals that there are only 13 stocks for which the volatilites for the simulated returns are smaller than those of the actual returns, and that when the volatilities of the simulated returns are larger than those of the actual returns they are much larger, for example .093 versus .065 for CAT and .132 versu .068 for HD

Main message: It is not safe to use normal distributions in modeling stock returns with a fundamental factor model (or otherwise). It is for this reason that fmmcSemiParam allows you to use skewed t-distributions and Cornish-Fisher quantile rerpresentation of non-normal distributions for the residuals.

4. Market plus Industry plus Country Model

In this discussion we treat the terms “Industry” and “Sector” interchangeably, noting that for some models, e.g., a U.S. equity model, one may prefer to just use sector factors but may also wish to use industry factors, and a global model with countries may also contain industry factors. Our current examples use sector factors but we refer to them in our mathematical models loosely as industry factors.

We will illustrate use of fitFfm to fit a market plus sector model to the DJIA stock returns and sector data. But first we fit a pure sector model without a market component and examine the factor return coefficients for the first month of the five-year fitting window as a reference point.


dat = factorDataSetDjia5Yrs 
fitSec = fitFfm(dat,
                asset.var = "TICKER",
                ret.var = "RETURN", 
                date.var = "DATE",
                exposure.vars = "SECTOR") 

round(coef(summary(fitSec)$sum.list[[1]])[, 1], 3) 
COSTAP ENERGY   FINS HEALTH INDUST INFOTK MATRLS TELCOM 
-0.007  0.034 -0.121 -0.028 -0.016  0.037  0.082 -0.080 
round(fitSec$factor.returns[1, ], 3) 
           COSTAP ENERGY   FINS HEALTH INDUST INFOTK MATRLS TELCOM
2008-02-01 -0.007  0.034 -0.121 -0.028 -0.016  0.037  0.082  -0.08

Note that the last two lines of code produce identical results. This is because without any constraints such as those discussed above, the coefficients of the cross-section regression at each time period are extracted to form the time series of factor returns in the factor.returns component of the ffm object. Now we fit a market plus sector model by adding the fitF argument addIntercept = T,and examine the coefficients gˆmi,1 and the resulting factor returns ˆfmi,1 for the first month of the fiveyear fitting window.


fitSecInt = fitFfm(dat,
                   asset.var = "TICKER",
                   ret.var = "RETURN", 
                   date.var = "DATE",
                   exposure.vars = "SECTOR",
                   addIntercept = T) 

round(coef(summary(fitSecInt)$sum.list[[1]])[, 1], 2) 
   g1    g2    g3    g4    g5    g6    g7    g8 
-0.01  0.01  0.05 -0.11 -0.02  0.00  0.05  0.09 
#excactly the same as before, but we add intercept t; therefore we add the market component

round(fitSecInt$factor.returns[1, ], 2) 
           Market COSTAP ENERGY  FINS HEALTH INDUST INFOTK MATRLS TELCOM
2008-02-01  -0.01   0.01   0.05 -0.11  -0.02      0   0.05   0.09  -0.07

round(sum(fitSecInt$factor.returns[1, -1]), 2) 
[1] 0
# Summed returns of all sector should equal to zero, due to the relationship of the sectors

Note that the next to last line of code above prints the unique least squares model coefficients vector gˆmi,1 for month 1 (9 of them since there are 9 sectors)

5. A Simultated Data Example

We have created an artificial example of a market+sector+country model (where sector plays the role of industry) consisting of random returns of 30 stocks with three sectors for the sector factor and two countries for the countries factor, for each of five months. The normally distributed returns for the three sectors alone have means of 1, 2, 3, with standard deviations .2. The two countries contribute additional normally distributed returns having means 4 and 5 with standard deviations .2. So returns associated with the first country have means 5, 6, 7 and means associated with the second country have means 6, 7, 8. Thus the overall mean of 6.5. The code for creating the returns is as follows:


# Country Incremental Components of Asset Returns 
set.seed(10000)

Bind = cbind(rep(1, 30), 
             c(rep(1, 10), rep(0, 20)), 
             c(rep(0, 10), rep(1, 10), rep(0, 10)), 
             c(rep(0, 20), rep(1, 10))) 

cty1 = matrix(rep(c(0, 1), 15)) 

cty2 = matrix(rep(c(1, 0), 15)) 

Bmic = cbind(Bind, cty1, cty2) 

dimnames(Bmic)[[2]] = c("mkt", "sec1", "sec2", "sec3", "cty1", "cty2") 

r.add = rnorm(30, 4, 0.2) 
r.cty1 = rep(0, 30) 
r.cty2 = rep(0, 30) 

for (i in 1:30) 
  {
  if (Bmic[i, "cty1"] == 1) 
    { 
    r.cty1[i] = r.add[i] 
    r.cty2[i] = 0 
    } 
  else 
    { 
      r.cty1[i] = 0
      r.cty2[i] = r.add[i] + 1
    } 
  } 


# Asset Returns for Market+Industry+Country Model 
mu = c(1, 2, 3) 
sd = c(0.2, 0.2, 0.2) 
r = list() 
r.mic = list() 
fitMic = list() 
fitMic1 = list() 

for (i in 1:5) 
  {
  set.seed(1099923 + (i - 1)) 
  r[[i]] = c(rnorm(10, mu[1], sd[1]), 
             rnorm(10, mu[2], sd[2]), 
             rnorm(10, mu[3], sd[3])) 
  r.mic[[i]] = r[[i]] + r.cty1 + r.cty2 
  } 

#qq-plot of the 30 asset returns for the first of the 5 time periods 
#Die Beobachtungswerte zweier Merkmale, deren Verteilung man vergleichen will, werden jeweils der Größe nach geordnet. Diese geordneten Daten werden zu Wertepaaren zusammengefasst und in einem Koordinatensystem abgetragen. Ergeben die Punkte (annähernd) eine Gerade, kann man vermuten, dass den beiden Merkmalen die gleiche Verteilung zu Grunde liegt. Problematisch ist das Verfahren, wenn von den beiden Merkmalen unterschiedlich viele Beobachtungen vorliegen. Hier kann mit Interpolationsverfahren abgeholfen werden.
qqnorm(r.mic[[1]],
       main = "MIC Model Equity Returns for First Period", 
       xlab = "NORMAL QQ-PLOT",
       ylab = "RETURNS") 

NA

Now we build the data frame required by fitFfm, fit the MIC model and display the factor returns for each of the five months. What we have been calling the Industry factor is called Sector for this example


Returns = unlist(r.mic) 

COUNTRY = rep(rep(c("US", "India"), 15), 5) 

SECTOR = rep(rep(c("SEC1", "SEC2", "SEC3"), each = 10), 5) 

TICKER = rep(c(LETTERS[1:26], paste0("A", LETTERS[1:4])), 5) 

DATE = rep(seq(as.Date("2000/1/1"), by = "month", length.out = 5), each = 30) 

data.mic = data.frame(DATE = as.character(DATE),
                      TICKER, 
                      Returns, 
                      SECTOR, 
                      COUNTRY) 

exposure.vars = c("SECTOR", "COUNTRY") 

fit = fitFfm(data = data.mic,
             asset.var = "TICKER", 
             ret.var = "Returns",
             date.var = "DATE",
             exposure.vars = exposure.vars, 
             addIntercept = T) 

fit$factor.returns 
           Market   SEC1     SEC2  SEC3  India    US
2000-02-01   6.50 -0.964 -0.00539 0.970 -0.501 0.501
2000-03-01   6.53 -0.965 -0.02718 0.993 -0.513 0.513
2000-04-01   6.52 -0.956 -0.00954 0.966 -0.513 0.513
2000-05-01   6.58 -1.008 -0.02796 1.036 -0.516 0.516

We see that the Market values of the factor have values clustering around 6.5 as expected. We can also see that the three sector factor returns sum to zero and the two country factor returns sum to zero, as expected due to the constraints that they sum to zero.

LS0tCnRpdGxlOiAiUG9ydGZvbGlvbWFuYWdlbWVudCBhbmQgRmluYW5jaWFsIEFuYWx5c2lzIC0gQXNzaWdubWVudCA2IgpzdWJ0aXRsZTogIlN1Ym1pdCB1bnRpbCBNb25kYXkgMjAyMC0xMS0wMiwgMTM6MDAiCmF1dGhvcjogIlN0ZWZhbiBNYWNhbm92aWMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIHNldHVwfQpyZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiYnJhdmVyb2NrL2ZhY3RvckFuYWx5dGljcyIsICBidWlsZF92aWduZXR0ZXMgPSBUUlVFLCBmb3JjZSA9IFRSVUUpCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSx0aWR5cXVhbnQsRkZkb3dubG9hZCxGYWN0b3JBbmFseXRpY3MsUGVyZm9ybWFuY2VBbmFseXRpY3MpCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSx0aWR5cXVhbnQsRkZkb3dubG9hZCxQb3J0Zm9saW9BbmFseXRpY3MsbmxvcHRyKQpwYWNtYW46OnBfbG9hZCh0aWR5dmVyc2UsdGlkeXF1YW50LFBvcnRmb2xpb0FuYWx5dGljcyxubG9wdHIsdHNpYmJsZSxtYXRyaXhjYWxjLE1hdHJpeCx0aW1ldGsseHRzKQpgYGAKCmBgYHtyfQojIyBJbXBvcnRhbnQgRnVuY3Rpb24KCiMgICAgICAgZml0VHNmbQojICAgCiMgICAgIGZpdFRzZm0oYXNzZXQubmFtZXMsIGZhY3Rvci5uYW1lcywgZGF0YSwgZml0Lm1ldGhvZCwgdmFyaWFibGUuc2VsZWN0aW9uLCAuLi4pOgojICAgICAKIyAgICAgRml0cyBhIHRpbWUgc2VyaWVzIChhLmsuYS4gbWFjcm9lY29ub21pYykgZmFjdG9yIG1vZGVsIGZvciBvbmUgb3IgbW9yZSBhc3NldCByZXR1cm5zIG9yIGV4Y2VzcwojICAgICByZXR1cm5zIHVzaW5nIHRpbWUgc2VyaWVzIHJlZ3Jlc3Npb24uIExlYXN0IHNxdWFyZXMgKExTKSwgZGlzY291bnRlZCBsZWFzdCBzcXVhcmVzIChETFMpIGFuZAojICAgICByb2J1c3QgcmVncmVzc2lvbiBmaXR0aW5nIGFyZSBwb3NzaWJsZS4gVmFyaWFibGUgc2VsZWN0aW9uIG1ldGhvZHMgaW5jbHVkZSAic3RlcHdpc2UiLCAic3Vic2V0cyIgYW5kICJsYXJzIi4gQW4gb2JqZWN0IG9mIGNsYXNzICJ0c2ZtIiBjb250YWluaW5nIHRoZQojICAgICBmaXR0ZWQgb2JqZWN0cywgZXN0aW1hdGVkIGNvZWZmaWNpZW50cywgUi1zcXVhcmVkIGFuZCByZXNpZHVhbCB2b2xhdGlsaXR5IGlzIHJldHVybmVkLgoKYGBgCgoKKipQbGVhc2UqKiByZW1lbWJlciB0byBwdXQgeW91ciBhc3NpZ25tZW50IHNvbHV0aW9ucyBpbiBgcm1kYCBmb3JtYXQgdXNpbmcgKiptYW55KiogY2h1bmtzIGFuZCBwdXR0aW5nIHJlYWRhYmxlIHRleHQgaW4gYmV0d2Vlbiwgc2ltaWxhciB0byBteSBleGFtcGxlcyBnaXZlbiBpbiBSZXNlYXJjaCBNZXRob2RzIGFuZCBBc3NpZ25tZW50IDEhCgpGb3IgYWxsIGV4ZXJjaXNlczogUGxlYXNlIHVzZSB0aGUgQXNzaWdubWVudC1Gb3J1bSB0byBwb3N0IHlvdXIgcXVlc3Rpb25zLCBJIHdpbGwgdHJ5IG15IGJlc3QgdG8gaGVscCB5b3UgYWxvbmchIElmIHlvdSBmb2xsb3cgdGhlIHZpZ25ldHRlcyBmcm9tIGBmYWN0b3JBbmFseXRpY3NgLCB3aGVyZXZlciBpdCBzYXlzIGB6LnNjb3JlPVRgLCBwbGVhc2UgZXhjaGFuZ2UgaXQgZm9yIGVpdGhlciBgei5zY29yZT0nY3Jvc3NTZWN0aW9uJ2Agb3IgYHouc2NvcmU9J3RpbWVTZXJpZXMnYCBkZXBlbmRpbmcgb24gdGhlIHRhc2sgYXQgaGFuZC4KCiMjIEV4ZXJjaXNlIDE6IEVzdGltYXRpbmcgdGhlIENBUE0gKGZyb20gQTA1KQoKSW4gdGhpcyBleGVyY2lzZSB3ZSB3YW50IHRvIGVzdGltYXRlIHRoZSBDQVBNLiBQbGVhc2UgcmVhZCBjYXJlZnVsbHkgdGhyb3VnaCB0aGUgdHdvIGRvY3VtZW50cyBwcm92aWRlZCAocmlnaHQgaGFuZCBzaWRlOiBmaWxlcykuIFRoZW4gd2Ugc3RhcnQgdG8gY29sbGVjdCB0aGUgbmVjZXNzYXJ5IGRhdGE6CiAgCmEpIEZyb20gRGF0YXN0cmVhbSBnZXQgdGhlIGxhc3QgMTAgeWVhcnMgb2YgZGF0YSBmcm9tIHRoZSAxMDAgc3RvY2tzIG9mIHRoZSBTJlAxMDAgdXNpbmcgdGhlIGxpc3QgYExTJlAxMDBJYCAoUyZQIDEwMCk6IHRvdGFsIHJldHVybiBpbmRleCAoUkkpIGFuZCBtYXJrZXQgY2FwIChNVikKYikgRnVydGhlciBpbXBvcnQgdGhlIEZhbWEtRnJlbmNoLUZhY3RvcnMgZnJvbSBLZW5uZXRoIEZyZW5jaHMgaG9tZXBhZ2UgKG1vbnRobHksIGUuZy4gdXNpbmcgYEZGZG93bmxvYWRgKS4gRnJvbSBib3RoIGRhdGFzZXRzIHdlIHNlbGVjdCBkYXRhIGZvciB0aGUgbGFzdCAoYXZhaWxhYmxlKSA2MCBtb250aHMsIGNhbGN1bGF0ZSByZXR1cm5zIChzaW1wbGUgcGVyY2VudGFnZSkgZm9yIHRoZSBVUy1TdG9ja3MgYW5kIGVsaW1pbmF0ZSB0aG9zZSBzdG9ja3MgdGhhdCBoYXZlIE5BcyBmb3IgdGhpcyBwZXJpb2QuCmMpIE5vdyBzdWJ0cmFjdCB0aGUgcmlzay1mcmVlIHJhdGUgZnJvbSBhbGwgdGhlIHN0b2Nrcy4gVGhlbiBlc3RpbWF0ZSBlYWNoIHN0b2NrcyBiZXRhIHdpdGggdGhlIG1hcmtldDogUmVncmVzcyBhbGwgc3RvY2sgZXhjZXNzIHJldHVybnMgb24gdGhlIG1hcmtldCBleGNlc3MgcmV0dXJuIGFuZCBzYXZlIGFsbCBiZXRhcyAob3B0aW1hbGx5IHVzZSBgbXV0YXRlYCBhbmQgYG1hcGAgaW4gY29tYmluYXRpb24gd2l0aCBgbG1gKS4gRXN0aW1hdGUgdGhlIG1lYW4tcmV0dXJuIGZvciBlYWNoIHN0b2NrIGFuZCBwbG90IHRoZSByZXR1cm4vYmV0YS1jb21iaW5hdGlvbnMuIENyZWF0ZSB0aGUgc2VjdXJpdHkgbWFya2V0IGxpbmUgYW5kIGluY2x1ZGUgaXQgaW4gdGhlIHBsb3QhIFdoYXQgZG8geW91IGZpbmQ/CmQpIEluIGEgbmV4dCBzdGVwIChmb2xsb3dpbmcgYm90aCBkb2N1bWVudHMpLCB3ZSBzb3J0IHRoZSBzdG9ja3MgYWNjb3JkaW5nIHRvIHRoZWlyIGJldGEgYW5kIGJ1aWxkIHRlbiB2YWx1ZS13ZWlnaHRlZCBwb3J0Zm9saW9zICh3aXRoIG1vcmUgb3IgbGVzcyB0aGUgc2FtZSBudW1iZXIgb2Ygc3RvY2tzKS4gUmVwZWF0IGEpIGZvciB0aGUgdGVuIHBvcnRmb2xpb3MuIFdoYXQgZG8geW91IG9ic2VydmU/CmUpIEluIHRoZSB0aGlyZCBzdGVwIHlvdSBmb2xsb3cgcGFnZSA2LTggb2YgdGhlIHNlY29uZCBkb2N1bWVudCBhbmQgZXN0aW1hdGUgdGhlIHNlY29uZC1wYXNzIHJlZ3Jlc3Npb24gd2l0aCB0aGUgbWFya2V0IGFuZCB0aGVuIG1hcmtldCAmIGlkaW9zeW5jcmF0aWMgcmlzay4gV2hhdCBkbyB5b3Ugb2JzZXJ2ZT8gUHJlc2VudCBhbGwgeW91ciByZXN1bHRzIGluIGEgc2ltaWxhciBmYXNoaW9uIGFzIGluIHRoZSBkb2N1bWVudC4KCiMjIEV4ZXJjaXNlIDI6IENhbGN1bGF0aW5nIGFuZCBjaGVja2luZyB0aGUgQ0FQTSBjb250LiAoZnJvbSBBMDUpCgpgYGB7cn0KcGFjbWFuOjpwX2xvYWQodGlkeXZlcnNlLHRpZHlxdWFudCxGRmRvd25sb2FkLFBvcnRmb2xpb0FuYWx5dGljcyxubG9wdHIscmVhZHhsLHF1YW50bW9kLEZGZG93bmxvYWQsdGltZXRrLCBkcGx5ciwgeHRzKQpgYGAKCgpBcyB3ZSBoYXZlIHNlZW46IHRoZSBDQVBNIGZvciBzbWFsbCBwb3J0Zm9saW9zIGRvZXMgbm90IHdvcmsgdmVyeSB3ZWxsLCBhbmQgc28gd2Ugc3RhcnQgdXNpbmcgcG9ydGZvbGlvcyB0aGF0IGdldCByaWQgb2YgdGhlIGlkaW9zeW5jcmF0aWMgcmlzayEKR28gdG8gS2VubmV0aCBGcmVuY2gncyBIb21lcGFnZSAgYWdhaW4gYW5kIGRvd25sb2FkIHRoZSBmb2xsb3dpbmcgZGF0YXNldHM6ICJQb3J0Zm9saW9zIEZvcm1lZCBvbiBNYXJrZXQgQmV0YSIgKHdoZXJlIHdlIHdpbGwgdXNlIDEwIG1vbnRobHkgdmFsdWUgd2VpZ2h0ZWQgcG9ydGZvbGlvcyBmb3JtZWQgb24gYmV0YSkgYW5kICIyNSBQb3J0Zm9saW9zIEZvcm1lZCBvbiBTaXplIGFuZCBNYXJrZXQgQmV0YSIgKHNhbWUgdGhpbmcpIGFzIHdlbGwgYXMgdGhlIG1hcmtldCBmYWN0b3IgYW5kIHJmIChhcyBiZWZvcmUpLiBOb3cgd2UgYXJlIGdvaW5nIHRvIGNoZWNrIHRoZSBDQVBNIGxpa2UgZmFtb3VzIHJlc2VhcmNoZXJzIGhhdmUgZG9uZSBpdCEKV2UgY2FuIHVzZSByZXR1cm5zIGFzIHRoZXkgYXJlIGluIHRoZSBmaWxlcyAoc2ltcGxlIHJldHVybnMpIQoKCmBgYHtyfQppbnB1dGxpc3Q8LWMoIkYtRl9SZXNlYXJjaF9EYXRhX0Zha3RvcnNfQ1NWLnppcCIsIlBvcnRmb2xpb3NfRm9ybWVkX29uX0JFVEFfQ1NWLnppcCIpCiAgICAgICAgICAgICAKI05vdyBwcm9jZXNzIG9ubHkgdGhlc2UgZmlsZXMgaWYgdGhleSBjYW4gYmUgbWF0Y2hlZCAoZG93bmxvYWQgb25seSkKRkZkb3dubG9hZChvdXRwdXRfZmlsZSA9ICJGRmRhdGEuUkRhdGEiLCBpbnB1dGxpc3QgPSBpbnB1dGxpc3QsIGV4Y2x1ZGVfZGFpbHk9VFJVRSkKCmxvYWQoIkZGZGF0YS5SRGF0YSIpCnBvcnRmX21rdF9iZXRhdGVzdDwtKEZGZG93bmxvYWQkeF9Qb3J0Zm9saW9zX0Zvcm1lZF9vbl9CRVRBJG1vbnRobHkkdmFsdWVfd2VpZ2h0ZWRfcmV0dXJucykKCnBvcnRmX21rdF9iZXRhdGVzdAoKYGBgCgoKCmBgYHtyfQojRG93bmxvYWQgdGhlIFBvcnRmb2xpb3MgZnJvbSBLZW5uZXRoIEZyZW5jaCdzIEhvbWVwYWdlCnBvcnRmX21rdF9iZXRhIDwtICJodHRwczovL21iYS50dWNrLmRhcnRtb3V0aC5lZHUvcGFnZXMvZmFjdWx0eS9rZW4uZnJlbmNoL2Z0cC9Qb3J0Zm9saW9zX0Zvcm1lZF9vbl9CRVRBX0NTVi56aXAiCiBwb3J0Zl9ta3RfYmV0YV9jc3YgPC0gIlBvcnRmb2xpb3NfRm9ybWVkX29uX0JFVEEuY3N2IgogdGVtcCA8LSB0ZW1wZmlsZSgpCmRvd25sb2FkLmZpbGUocG9ydGZfbWt0X2JldGEsIHRlbXAsIHF1aWV0ID0gVFJVRSkKcG9ydGZfbWt0X2JldGEgPC0gcmVhZF9jc3YodW56KHRlbXAsIHBvcnRmX21rdF9iZXRhX2NzdiksIHNraXAgPSAxNSwgcXVvdGUgPSAiXCIsIikgJT4lCiAgZHBseXI6OnJlbmFtZShkYXRlID0gIlgxIikgJT4lCiAgbXV0YXRlX2F0KHZhcnMoLWRhdGUpLCBhcy5udW1lcmljKSAlPiUKICBtdXRhdGUoZGF0ZSA9IHJvbGxiYWNrKHltZChwYXJzZV9kYXRlX3RpbWUoZGF0ZSwgIiVZJW0iKSArIG1vbnRocygxKSkpKSU+JQogIGZpbHRlcihkYXRlID49IGZpcnN0KCcxOTY0LTAxLTAxJykgJiBkYXRlIDw9ICcyMDE5LTEyLTMxJykKCiNEb3dubG9hZCB0aGUgbWFya2V0IGZhY3RvciBhbmQgcmYgKEZhbWEvRnJlbmNoIDMgUmVzZWFyY2ggRmFjdG9ycykKbWt0X2ZhY3RvcnMgPC0gImh0dHBzOi8vbWJhLnR1Y2suZGFydG1vdXRoLmVkdS9wYWdlcy9mYWN1bHR5L2tlbi5mcmVuY2gvZnRwL0YtRl9SZXNlYXJjaF9EYXRhX0ZhY3RvcnNfQ1NWLnppcCIKIG1rdF9mYWN0b3JzX2NzdiA8LSAiRi1GX1Jlc2VhcmNoX0RhdGFfRmFjdG9ycy5DU1YiCiB0ZW1wIDwtIHRlbXBmaWxlKCkKZG93bmxvYWQuZmlsZShta3RfZmFjdG9ycywgdGVtcCwgcXVpZXQgPSBUUlVFKQpta3RfZmFjdG9ycyA8LSByZWFkX2Nzdih1bnoodGVtcCwgbWt0X2ZhY3RvcnNfY3N2KSwgc2tpcCA9IDMsIHF1b3RlID0gIlwiLCIpICU+JQogIGRwbHlyOjpyZW5hbWUoZGF0ZSA9IFgxKSAlPiUKICBtdXRhdGVfYXQodmFycygtZGF0ZSksIGFzLm51bWVyaWMpICU+JQogIG11dGF0ZShkYXRlID0gcm9sbGJhY2soeW1kKHBhcnNlX2RhdGVfdGltZShkYXRlLCAiJVklbSIpICsgbW9udGhzKDEpKSkpICU+JQogIGZpbHRlcihkYXRlID49IGZpcnN0KCcxOTY0LTAxLTAxJykgJiBkYXRlIDw9ICcyMDE5LTEyLTMxJykKCgpgYGAKCgphKQlTdWJ0cmFjdCB0aGUgcmlzay1mcmVlIHJhdGUgZnJvbSB0aGUgZmlyc3Qgc2V0IG9mIDEwIHBvcnRmb2xpb3MgKG9ubHkgc29ydGVkIG9uIGJldGEpIChMbyAxMCwuLCBIaSAxMCkgYW5kIGVzdGltYXRlIGVhY2ggc3RvY2tzIGJldGEgd2l0aCB0aGUgbWFya2V0LiBFc3RpbWF0ZSB0aGUgbWVhbi1yZXR1cm4gZm9yIGVhY2ggc3RvY2sgYW5kIHBsb3QgdGhlIHJldHVybi9iZXRhLWNvbWJpbmF0aW9ucy4gQ3JlYXRlIHRoZSBzZWN1cml0eSBtYXJrZXQgbGluZSBhbmQgaW5jbHVkZSBpdCBpbiB0aGUgcGxvdCEgV2hhdCBkbyB5b3UgZmluZD8gKFlvdSBjYW4gc3BsaXQgdGhlIGZpbGUgaW4gMi0zIGRpZmZlcmVudCB0aW1lIGJsb2NrcyBhbmQgc2VlIGlmIHNvbWV0aGluZyBjaGFuZ2VzKS4gKiBOb3cgd2UgYXJlIGRvbmUgd2l0aCB0aGUgZmlyc3QtcGFzcyByZWdyZXNzaW9uLioKCgpTdWJ0cmFjdCB0aGUgcmlzay1mcmVlIHJhdGUgZnJvbSB0aGUgZmlyc3Qgc2V0IG9mIDEwIHBvcnRmb2xpb3MgKG9ubHkgc29ydGVkIG9uIGJldGEpIChMbyAxMCwuLCBIaSAxMCkgYW5kIGVzdGltYXRlIGVhY2ggc3RvY2tzIGJldGEgd2l0aCB0aGUgbWFya2V0LgoKYGBge3J9CiNqb2luIGRhdGEKdGVuX3BvcnRmIDwtIHBvcnRmX21rdF9iZXRhWzE6NjcyLCAtYygyOjYpXQp0ZW5fcG9ydGZfam9pbmVkIDwtIGxlZnRfam9pbihta3RfZmFjdG9ycywgdGVuX3BvcnRmKQoKbWt0X2ZhY3RvcnMKdGVuX3BvcnRmCnRlbl9wb3J0Zl9qb2luZWQKCmBgYApgYGB7ciwgZWNobz1GQUxTRX0KdGVuX3BvcnRmX2pvaW5lZCA8LSB0ZW5fcG9ydGZfam9pbmVkIDwtIHRlbl9wb3J0Zl9qb2luZWQlPiUgZHBseXI6OnJlbmFtZSgiTG8xMCIgPSAiTG8gMTAiKSAlPiUgZHBseXI6OnJlbmFtZSgiRGVjMiIgPSAiRGVjIDIiKSAlPiUgZHBseXI6OnJlbmFtZSgiRGVjMyIgPSAiRGVjIDMiKSAlPiUgZHBseXI6OnJlbmFtZSgiRGVjNCIgPSAiRGVjIDQiKSAlPiUgZHBseXI6OnJlbmFtZSgiRGVjNSIgPSAiRGVjIDUiKSAlPiUgZHBseXI6OnJlbmFtZSgiRGVjNiIgPSAiRGVjIDYiKSAlPiUgZHBseXI6OnJlbmFtZSgiRGVjNyIgPSAiRGVjIDciKSAlPiUgZHBseXI6OnJlbmFtZSgiRGVjOCIgPSAiRGVjIDgiKSAlPiUgZHBseXI6OnJlbmFtZSgiRGVjOSIgPSAiRGVjIDkiKSAlPiUgZHBseXI6OnJlbmFtZSgiSGkxMCIgPSAiSGkgMTAiKQoKdmlldyh0ZW5fcG9ydGZfam9pbmVkKQp0ZW5fcG9ydGZfam9pbmVkCgpgYGAKCmBgYHtyfQojc3Vic3RyYWN0IFJpc2stRnJlZS1SYXRlCnRlbl9wb3J0Zl9yZiA8LSBtdXRhdGUodGVuX3BvcnRmX2pvaW5lZCwgTG8xMHJmID0gTG8xMCAtIFJGLCBEZWMycmYgPSBEZWMyIC0gUkYsIERlYzNyZiA9IERlYzMgLSBSRiwgRGVjNHJmID0gRGVjNCAtIFJGLCBEZWM1cmYgPSBEZWM1IC1SRiwgRGVjNnJmID0gRGVjNiAtIFJGLCBEZWM3cmYgPSBEZWM3IC0gUkYsIERlYzhyZiA9IERlYzggLSBSRiwgRGU5cmYgPSBEZWM5IC0gUkYsIEhpMTByZiA9IEhpMTAgLSBSRikKdGVuX3BvcnRmX3JmIDwtIHRlbl9wb3J0Zl9yZlstMjotMTVdCgp2aWV3KHRlbl9wb3J0Zl9yZikKdGVuX3BvcnRmX3JmCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CiNDcmVhdGUgWFRTCm1rdF9mYWN0b3JzX3h0cyA8LSB0a194dHMoZGF0YSA9IG1rdF9mYWN0b3JzLCBkYXRlX3ZhciA9IGRhdGUpCnRlbl9wb3J0Zl9yZl94dHMgPC0gdGVuX3BvcnRmX3JmICU+JQogIHRrX3h0cyhkYXRlX3ZhciA9IGRhdGUsIHNpbGVudCA9IFRSVUUpCgpgYGAKYGBge3J9Cj9sbSgpCiNDYWxjdWxhdGUgQmV0YXMgZm9yIGVhY2ggcG9ydGZvbGlvCmJldGFzX3Rlbl9wb3J0Zl9sbSA8LSBsbSh0ZW5fcG9ydGZfcmZfeHRzIH4gbWt0X2ZhY3RvcnNfeHRzWywgMV0pCmJldGFzX3Rlbl9wb3J0Zl9sbQpiZXRhc190ZW5fcG9ydGYgPC0gQ0FQTS5iZXRhKFJhID0gdGVuX3BvcnRmX3JmX3h0cywgUmIgPSBta3RfZmFjdG9yc194dHNbLCAxXSwgUmYgPSAwKQpiZXRhc190ZW5fcG9ydGYKYGBgCkVzdGltYXRlIHRoZSBtZWFuLXJldHVybiBmb3IgZWFjaCBzdG9jayBhbmQgcGxvdCB0aGUgcmV0dXJuL2JldGEtY29tYmluYXRpb25zLgoKYGBge3J9CiNFc3RpbWF0ZSBNZWFuIFJldHVybgptZWFuX3Rlbl9wb3J0Zl9yZl94dHMgPC0gYXMuZGF0YS5mcmFtZShsYXBwbHkodGVuX3BvcnRmX3JmX3h0cywgRlVOPW1lYW4pKQptZWFuX3Rlbl9wb3J0Zl9yZl94dHMKCiNQbG90IHRoZSByZXR1cm4vYmV0YS1jb21iaW5hdGlvbnMKcGxvdC5kZWZhdWx0KHggPSBiZXRhc190ZW5fcG9ydGYsIHhsaW09YygwLCAyKSwKICAgICAgICAgICAgIHkgPSBtZWFuX3Rlbl9wb3J0Zl9yZl94dHMsIHlsaW09YygwLCAxKSwKICAgICAgICAgICAgIHhsYWIgPSAiQmV0YSIsIHlsYWIgPSAiTWVhbiBSZXR1cm4iLAogICAgICAgICAgICAgbWFpbiA9ICJSZXR1cm4vQmV0YS1jb21iaW5hdGlvbnMiKQpgYGAKQ3JlYXRlIHRoZSBzZWN1cml0eSBtYXJrZXQgbGluZSBhbmQgaW5jbHVkZSBpdCBpbiB0aGUgcGxvdCEgV2hhdCBkbyB5b3UgZmluZD8KCmBgYHtyfQptZWFuX21rdCA8LSBhcy5kYXRhLmZyYW1lKGxhcHBseShta3RfZmFjdG9yc194dHNbLCAxXSwgRlVOPW1lYW4pKQp5X21rdCA8LSBtZWFuX21rdFsxLCAxXQpwbG90LmRlZmF1bHQoeCA9IGJldGFzX3Rlbl9wb3J0ZiwgeGxpbT1jKDAsIDIpLAogICAgICAgICAgICAgeSA9IG1lYW5fdGVuX3BvcnRmX3JmX3h0cywgeWxpbT1jKDAsIDEpLAogICAgICAgICAgICAgeGxhYiA9ICJCZXRhIiwgeWxhYiA9ICJNZWFuIFJldHVybiIsCiAgICAgICAgICAgICBtYWluID0gIlJldHVybi9CZXRhLWNvbWJpbmF0aW9ucyIsCiAgICAgICAgICAgICBhYmxpbmUoMCwgeV9ta3QpKQpwbG90LmRlZmF1bHQoeCA9IGJldGFzX3Rlbl9wb3J0ZiwgeGxpbT1jKDAsIDIpLCAKICAgICAgICAgICAgIHkgPSBtZWFuX3Rlbl9wb3J0Zl9yZl94dHMsIHlsaW09YygwLCAxMCksIAogICAgICAgICAgICAgeGxhYiA9ICJCZXRhIiwgeWxhYiA9ICJNZWFuIFJldHVybiIsCiAgICAgICAgICAgICBtYWluID0gIlJldHVybi9CZXRhLWNvbWJpbmF0aW9ucyIsCiAgICAgICAgICAgICBhYmxpbmUoMCwgeV9ta3QpKQoKI3N1bW1hcnkKc3VtbWFyeV9DQVBNX3Rlbl9wb3J0ZiA8LSAodGFibGUuQ0FQTShSYSA9IHRlbl9wb3J0Zl9yZl94dHMsIFJiID0gbWt0X2ZhY3RvcnNfeHRzWywgMV0sIFJmID0gMClbMTo5LCBdKQpgYGAKKFlvdSBjYW4gc3BsaXQgdGhlIGZpbGUgaW4gMi0zIGRpZmZlcmVudCB0aW1lIGJsb2NrcyBhbmQgc2VlIGlmIHNvbWV0aGluZyBjaGFuZ2VzKS4gKiBOb3cgd2UgYXJlIGRvbmUgd2l0aCB0aGUgZmlyc3QtcGFzcyByZWdyZXNzaW9uLioKCmBgYHtyfQojbG9vayBmb3IgZmlyc3QgMTAgeWVhcnMKdGVuX3BvcnRmX3JmXzEweXJzX3h0cyA8LSB0ZW5fcG9ydGZfcmZbMToxMjAsIF0gJT4lCiAgdGtfeHRzKGRhdGVfdmFyID0gZGF0ZSwgc2lsZW50ID0gVFJVRSkKYmV0YXNfdGVuX3BvcnRmX3JmXzEweXJzIDwtIENBUE0uYmV0YShSYSA9IHRlbl9wb3J0Zl9yZl8xMHlyc194dHMsIFJiID0gbWt0X2ZhY3RvcnNfeHRzWzE6MTIwLCAxXSwgUmYgPSAwKQptZWFuX3Rlbl9wb3J0Zl9yZl8xMHlyc194dHMgPC0gYXMuZGF0YS5mcmFtZShsYXBwbHkodGVuX3BvcnRmX3JmXzEweXJzX3h0cywgRlVOPW1lYW4pKQptZWFuX21rdF8xMHlycyA8LSBhcy5kYXRhLmZyYW1lKGxhcHBseShta3RfZmFjdG9yc194dHNbMToxMjAsIDFdLCBGVU49bWVhbikpCnlfbWt0XzEweXJzIDwtIG1lYW5fbWt0XzEweXJzWzEsIDFdCnBsb3QuZGVmYXVsdCh4ID0gYmV0YXNfdGVuX3BvcnRmX3JmXzEweXJzLCB4bGltPWMoMCwgMiksCiAgICAgICAgICAgICB5ID0gbWVhbl90ZW5fcG9ydGZfcmZfMTB5cnNfeHRzLCB5bGltPWMoMCwgMSksCiAgICAgICAgICAgICB4bGFiID0gIkJldGEiLCB5bGFiID0gIk1lYW4gUmV0dXJuIiwKICAgICAgICAgICAgIG1haW4gPSAiUmV0dXJuL0JldGEtY29tYmluYXRpb25zIDE5NjQtMTk3NCIsCiAgICAgICAgICAgICBhYmxpbmUoMCwgeV9ta3RfMTB5cnMpKQpzdW1tYXJ5X0NBUE1fdGVuX3BvcnRmXzEweXJzIDwtICh0YWJsZS5DQVBNKFJhID0gdGVuX3BvcnRmX3JmX3h0c1sxOjEyMCwgXSwgUmIgPSBta3RfZmFjdG9yc194dHNbMToxMjAsIDFdLCBSZiA9IDApWzE6OSwgXSkKc3VtbWFyeV9DQVBNX3Rlbl9wb3J0Zl8xMHlycwpgYGAKYGBge3IsIGVjaG89RkFMU0V9CgojbG9vayBmb3IgMjAwMC0yMDE5CnRlbl9wb3J0Zl9yZl8yMDAwX3h0cyA8LSB0ZW5fcG9ydGZfcmZbNDMzOjY3MiwgXSAlPiUKICB0a194dHMoZGF0ZV92YXIgPSBkYXRlLCBzaWxlbnQgPSBUUlVFKQpiZXRhc190ZW5fcG9ydGZfcmZfMjAwMCA8LSBDQVBNLmJldGEoUmEgPSB0ZW5fcG9ydGZfcmZfMjAwMF94dHMsIFJiID0gbWt0X2ZhY3RvcnNfeHRzWzQzMzo2NzIsIDFdLCBSZiA9IDApCm1lYW5fdGVuX3BvcnRmX3JmXzIwMDBfeHRzIDwtIGxhcHBseSh0ZW5fcG9ydGZfcmZfMjAwMF94dHMsIEZVTj1tZWFuKQptZWFuX3Rlbl9wb3J0Zl9yZl8yMDAwX3h0cyA8LSBhcy5kYXRhLmZyYW1lKG1lYW5fdGVuX3BvcnRmX3JmXzIwMDBfeHRzKQptZWFuX21rdF8yMDAwIDwtIGxhcHBseShta3RfZmFjdG9yc194dHNbNDMzOjY3MiwgMV0sIEZVTj1tZWFuKQptZWFuX21rdF8yMDAwIDwtIGFzLmRhdGEuZnJhbWUobWVhbl9ta3RfMjAwMCkKeV9ta3RfMjAwMCA8LSBtZWFuX21rdF8yMDAwWzEsIDFdCnBsb3QuZGVmYXVsdCh4ID0gYmV0YXNfdGVuX3BvcnRmX3JmXzIwMDAsIHhsaW09YygwLCAyKSwKICAgICAgICAgICAgIHkgPSBtZWFuX3Rlbl9wb3J0Zl9yZl8yMDAwX3h0cywgeWxpbT1jKDAsIDEpLAogICAgICAgICAgICAgeGxhYiA9ICJCZXRhIiwgeWxhYiA9ICJNZWFuIFJldHVybiIsCiAgICAgICAgICAgICBtYWluID0gIlJldHVybi9CZXRhLWNvbWJpbmF0aW9ucyAyMDAwLTIwMTkiLAogICAgICAgICAgICAgYWJsaW5lKDAsIHlfbWt0XzIwMDApKQpzdW1tYXJ5X0NBUE1fdGVuX3BvcnRmXzIwMDAgPC0gKHRhYmxlLkNBUE0oUmEgPSB0ZW5fcG9ydGZfcmZfeHRzWzQzMzo2NzIsIF0sIFJiID0gbWt0X2ZhY3RvcnNfeHRzWzQzMzo2NzIsIDFdLCBSZiA9IDApWzE6OSwgXSkKc3VtbWFyeV9DQVBNX3Rlbl9wb3J0Zl8yMDAwCgpwbG90LmRlZmF1bHQoeCA9IGJldGFzX3Rlbl9wb3J0ZiwgeGxpbT1jKDAsIDIpLAogICAgICAgICAgICAgeSA9IG1lYW5fdGVuX3BvcnRmX3JmX3h0cywgeWxpbT1jKDAsIDEpLAogICAgICAgICAgICAgeGxhYiA9ICJCZXRhIiwgeWxhYiA9ICJNZWFuIFJldHVybiIsCiAgICAgICAgICAgICBtYWluID0gIlJldHVybi9CZXRhLWNvbWJpbmF0aW9ucyAxOTY0LTIwMTkiLAogICAgICAgICAgICAgYWJsaW5lKDAsIHlfbWt0KSkKc3VtbWFyeV9DQVBNX3Rlbl9wb3J0ZgoKCmBgYAoKCmIpCUluIHRoZSBzZWNvbmQtcGFzcyByZWdyZXNzaW9uIHdlIG5vdyByZWdyZXNzIHRoZSBhdmVyYWdlIHN0b2NrIHJldHVybnMgb24gdGhlIGJldGFzIGVzdGltYXRlZCBiZWZvcmUuIFdoYXQgZG8geW91IGZpbmQgaW4gdGhlIGNvZWZmaWNpZW50cyBhbmQgZG9lcyB0aGlzIGNvbnRyYWRpY3QgdGhlIENBUE0/IFRyeSBkaWZmZXJlbnQgdGltZSBwZXJpb2RzIGFnYWluIGFuZCBzZWUgd2hhdCB5b3UgZmluZC4gKGFsbCBvZiB0aGUgaW50ZXJwcmV0YXRpb25zIGFyZSBpbiBCS00gcHAuNDE2ZikuIAoKCmBgYHtyfQpiZXRhc190ZW5fcG9ydGYKCgpgYGAKCmBgYHtyfQojVGhlcmUgYXJlIGEgbnVtYmVyIG9mIHJlYXNvbnMgd2UgZXhwZWN0IG1pZ2h0IHRoZSBDQVBNIHRvIGZhaWw6CiMxLiBJbXBlcmZlY3QgbWVhc3VyZXMgb2YgdGhlIG1hcmtldCBwb3J0Zm9saW8KIzIuIEJldGEgaXMgYW4gaW5jb21wbGV0ZSBtZWFzdXJlIG9mIHJpc2sKIzMuIFRheCBlZmZlY3RzCiM0LiBOb24gLSBub3JtYWxpdHkgb2YgcmV0dXJucwojNS4gTm8gcmlza2xlc3MgYXNzZXQKIzYuIERpdmVyZ2VudCBib3Jyb3dpbmcgYW5kIGxlbmRpbmcgcmF0ZXMKYGBgCgpUaGVyZSBhcmUgYSBudW1iZXIgb2YgcmVhc29ucyB3ZSBleHBlY3QgbWlnaHQgdGhlIENBUE0gdG8KZmFpbDoKMS4gSW1wZXJmZWN0IG1lYXN1cmVzIG9mIHRoZSBtYXJrZXQgcG9ydGZvbGlvCjIuIEJldGEgaXMgYW4gaW5jb21wbGV0ZSBtZWFzdXJlIG9mIHJpc2sKMy4gVGF4IGVmZmVjdHMKNC4gTm9uIC0gbm9ybWFsaXR5IG9mIHJldHVybnMKNS4gTm8gcmlza2xlc3MgYXNzZXQKNi4gRGl2ZXJnZW50IGJvcnJvd2luZyBhbmQgbGVuZGluZyByYXRlcwoKYykJTm93IGRvIHRoZSBleHRlbmRlZCBzZWNvbmQgcGFzcyByZWdyZXNzaW9uIChyZWdyZXNzIG9uIGJldGFzIGFuZCByZXNpZHVhbC1zZHMgdGhhdCB5b3UgY2FuIGV4dHJhY3QgZnJvbSB0aGUgcmVncmVzc2lvbikgYW5kIHNlZSB3aGF0IHlvdSBmaW5kIGZvciBkaWZmZXJlbnQgcGVyaW9kcy4gSW50ZXJwcmV0IGFjY29yZGluZyB0byBjb25jZXB0IGNoZWNrIDEzLjIuIE9uZSBvZiB0aGUgKG1hbnkpIHByb2JsZW1zIG9mIHRoZSBDQVBNIGNhbiBiZSB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiByZXNpZHVhbCB2YXJpYW5jZXMgYW5kIGJldGFzLiBDYWxjdWxhdGUgYW5kIGludGVycHJldC4KCmBgYHtyfQojTG9vayBhdCBhKSAtPiBXZSBub3cgZG8gaXQgd2l0aCB0aGUgbWVhbiByZXR1cm4gb2YgZXZlcnkgcG9ydGZvbGlvIGNvbWJpbmVkLi4uIAoKIzE5NjQtMjAxOQpjb21fbWVhbl90ZW5fcG9ydGZfcmYgPC0gc3VtKG1lYW5fdGVuX3BvcnRmX3JmX3h0cykvMTAKbWVhbl9iZXRhc190ZW5fcG9ydGYgPC0gc3VtKGJldGFzX3Rlbl9wb3J0ZikvMTAKcGxvdC5kZWZhdWx0KHggPSBtZWFuX2JldGFzX3Rlbl9wb3J0ZiwgeGxpbT1jKDAsIDIpLAogICAgICAgICAgICAgeSA9IGNvbV9tZWFuX3Rlbl9wb3J0Zl9yZiwgeWxpbT1jKDAsIDIpLAogICAgICAgICAgICAgeGxhYiA9ICJCZXRhIiwgeWxhYiA9ICJNZWFuIFJldHVybiIsCiAgICAgICAgICAgICBtYWluID0gIlJldHVybi9CZXRhLWNvbWJpbmF0aW9ucyAxMCBQb3J0Zm9saW9zIDE5NjQtMjAxOSIsCiAgICAgICAgICAgICBhYmxpbmUoMCwgeV9ta3QpKQoKCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CgojMTk2NC0xOTc0CmNvbV9tZWFuX3Rlbl9wb3J0Zl9yZl8xMHlycyA8LSBzdW0obWVhbl90ZW5fcG9ydGZfcmZfMTB5cnNfeHRzKS8xMAptZWFuX2JldGFzX3Rlbl9wb3J0Zl8xMHlycyA8LSBzdW0oYmV0YXNfdGVuX3BvcnRmX3JmXzEweXJzKS8xMApwbG90LmRlZmF1bHQoeCA9IG1lYW5fYmV0YXNfdGVuX3BvcnRmXzEweXJzLCB4bGltPWMoMCwgMiksCiAgICAgICAgICAgICB5ID0gY29tX21lYW5fdGVuX3BvcnRmX3JmXzEweXJzLCB5bGltPWMoMCwgMiksCiAgICAgICAgICAgICB4bGFiID0gIkJldGEiLCB5bGFiID0gIk1lYW4gUmV0dXJuIiwKICAgICAgICAgICAgIG1haW4gPSAiUmV0dXJuL0JldGEtY29tYmluYXRpb25zIDEwIFBvcnRmb2xpb3MgMTk2NC0xOTc0IiwKICAgICAgICAgICAgIGFibGluZSgwLCB5X21rdF8xMHlycykpCgojMjAwMC0yMDE5CmNvbV9tZWFuX3Rlbl9wb3J0Zl9yZl8yMDAwIDwtIHN1bShtZWFuX3Rlbl9wb3J0Zl9yZl8yMDAwX3h0cykvMTAKbWVhbl9iZXRhc190ZW5fcG9ydGZfMjAwMCA8LSBzdW0oYmV0YXNfdGVuX3BvcnRmX3JmXzIwMDApLzEwCnBsb3QuZGVmYXVsdCh4ID0gbWVhbl9iZXRhc190ZW5fcG9ydGZfMjAwMCwgeGxpbT1jKDAsIDIpLAogICAgICAgICAgICAgeSA9IGNvbV9tZWFuX3Rlbl9wb3J0Zl9yZl8yMDAwLCB5bGltPWMoMCwgMiksCiAgICAgICAgICAgICB4bGFiID0gIkJldGEiLCB5bGFiID0gIk1lYW4gUmV0dXJuIiwKICAgICAgICAgICAgIG1haW4gPSAiUmV0dXJuL0JldGEtY29tYmluYXRpb25zIDEwIFBvcnRmb2xpb3MgMjAwMC0yMDE5IiwKICAgICAgICAgICAgIGFibGluZSgwLCB5X21rdF8yMDAwKSkKCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CgojU01MLUZ1bmN0aW9uCmNhbGNfcmVzaWR1YWwgPC0gZnVuY3Rpb24oeCkge3kgPC0geV9ta3QqeH0KY2FsY19yZXNpZHVhbF8xMHlycyA8LSBmdW5jdGlvbih4KSB7eSA8LSB5X21rdF8xMHlycyp4fQpjYWxjX3Jlc2lkdWFsXzIwMDAgPC0gZnVuY3Rpb24oeCkge3kgPC0geV9ta3RfMjAwMCp4fQpyZXNpZHVhbF8xOTY0XzIwMTkgPC0gYXMuZGF0YS5mcmFtZSgoY29tX21lYW5fdGVuX3BvcnRmX3JmIC0gY2FsY19yZXNpZHVhbChtZWFuX2JldGFzX3Rlbl9wb3J0ZikpXjIpCnJlc2lkdWFsXzE5NjRfMTk3NCA8LSBhcy5kYXRhLmZyYW1lKChjb21fbWVhbl90ZW5fcG9ydGZfcmZfMTB5cnMgLSBjYWxjX3Jlc2lkdWFsXzEweXJzKG1lYW5fYmV0YXNfdGVuX3BvcnRmXzEweXJzKSleMikKcmVzaWR1YWxfMjAwMF8yMDE5IDwtIGFzLmRhdGEuZnJhbWUoKGNvbV9tZWFuX3Rlbl9wb3J0Zl9yZl8yMDAwIC0gY2FsY19yZXNpZHVhbF8yMDAwKG1lYW5fYmV0YXNfdGVuX3BvcnRmXzIwMDApKV4yKQpqb2luZWRfcmVzaWR1YWxzIDwtIG1lcmdlKHJlc2lkdWFsXzE5NjRfMjAxOVsxLCAxXSwgcmVzaWR1YWxfMTk2NF8xOTc0WzEsIDFdKQpqb2luZWRfcmVzaWR1YWxzIDwtIG1lcmdlKGpvaW5lZF9yZXNpZHVhbHMsIHJlc2lkdWFsXzIwMDBfMjAxOSkKUmVzaWR1YWxzX2RpZmZlcmVudF90aW1lcGVyaW9kcyA8LSBqb2luZWRfcmVzaWR1YWxzICU+JSAKICBkcGx5cjo6cmVuYW1lKCJSZXNpZHVhbCAyMDAwLTIwMTkiID0gIihjb21fbWVhbl90ZW5fcG9ydGZfcmZfMjAwMCAtIGNhbGNfcmVzaWR1YWxfMjAwMChtZWFuX2JldGFzX3Rlbl9wb3J0Zl8yMDAwKSleMiIpICU+JSBkcGx5cjo6cmVuYW1lKCJSZXNpZHVhbCAxOTY0LTIwMDgiID0gIngiKSAlPiUgZHBseXI6OnJlbmFtZSgiUmVzaWR1YWwgMTk2NC0xOTc0IiA9ICJ5IikKUmVzaWR1YWxzX2RpZmZlcmVudF90aW1lcGVyaW9kcwpgYGAKCgpkKQlUcnkgYWdhaW4gd2l0aCAyNSBwb3J0Zm9saW9zIHNvcnRlZCBvbiBzaXplIGFuZCBiZXRhLiBXaGF0IGRvIHlvdSBmaW5kPyBJcyB0aGF0IGludGVyZXN0aW5nPyAKCmBgYHtyfQppbnB1dGxpc3QxPC1jKCJGLUZfUmVzZWFyY2hfRGF0YV9GYWt0b3JzX0NTVi56aXAiLCIyNV9Qb3J0Zm9saW9zX0Zvcm1lZF9vbl9TaXplX2FuZCBNYXJrZXRfQmV0YV9DU1YuemlwIikKICAgICAgICAgICAgIAojTm93IHByb2Nlc3Mgb25seSB0aGVzZSBmaWxlcyBpZiB0aGV5IGNhbiBiZSBtYXRjaGVkIChkb3dubG9hZCBvbmx5KQpGRmRvd25sb2FkKG91dHB1dF9maWxlID0gIkZGZGF0YS5SRGF0YSIsIGlucHV0bGlzdCA9IGlucHV0bGlzdDEsIGV4Y2x1ZGVfZGFpbHk9VFJVRSkKCmxvYWQoIkZGZGF0YS5SRGF0YSIpCnR3ZW50eWZpdmVfcG9ydGY8LShGRmRvd25sb2FkJHhfMjVfUG9ydGZvbGlvc19Gb3JtZWRfb25fU2l6ZV9hbmRfTWFya2V0X0JldGEkbW9udGhseSR2YWx1ZV93ZWlnaHRlZF9yZXR1cm5zKQoKdHdlbnR5Zml2ZV9wb3J0ZgogCmBgYAoKYGBge3J9CmRvd25sb2FkLmZpbGUocG9ydGZfbWt0X2JldGEsIHRlbXAsIHF1aWV0ID0gVFJVRSkKcG9ydGZfbWt0X2JldGEgPC0gcmVhZF9jc3YodW56KHRlbXAsIHBvcnRmX21rdF9iZXRhX2NzdiksIHNraXAgPSAxNSwgcXVvdGUgPSAiXCIsIikgJT4lCiAgZHBseXI6OnJlbmFtZShkYXRlID0gIlgxIikgJT4lCiAgbXV0YXRlX2F0KHZhcnMoLWRhdGUpLCBhcy5udW1lcmljKSAlPiUKICBtdXRhdGUoZGF0ZSA9IHJvbGxiYWNrKHltZChwYXJzZV9kYXRlX3RpbWUoZGF0ZSwgIiVZJW0iKSArIG1vbnRocygxKSkpKSU+JQogIGZpbHRlcihkYXRlID49IGZpcnN0KCcxOTY0LTAxLTAxJykgJiBkYXRlIDw9ICcyMDE5LTEyLTMxJykKYGBgCgoKCmBgYHtyfQp0d2VudHlmaXZlX3BvcnRmCmBgYAoKCmBgYHtyfQojam9pbiBkYXRhCnR3ZW50eWZpdmVfcG9ydGYgPC0gcG9ydGZfbWt0X2JldGFbMTo2NzIsIC1jKDc6MTYpXQp0d2VudHlmaXZlX3BvcnRmX2pvaW5lZCA8LSBsZWZ0X2pvaW4obWt0X2ZhY3RvcnMsIHR3ZW50eWZpdmVfcG9ydGYpCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9Cgp0d2VudHlmaXZlX3BvcnRmX2pvaW5lZCA8LSB0d2VudHlmaXZlX3BvcnRmX2pvaW5lZCA8LSB0d2VudHlmaXZlX3BvcnRmX2pvaW5lZCU+JQogIGRwbHlyOjpyZW5hbWUoIkxvMjAiID0gIkxvIDIwIikgJT4lCiAgZHBseXI6OnJlbmFtZSgiUW50MiIgPSAiUW50IDIiKSAlPiUKICBkcGx5cjo6cmVuYW1lKCJRbnQzIiA9ICJRbnQgMyIpICU+JQogIGRwbHlyOjpyZW5hbWUoIlFudDQiID0gIlFudCA0IikgJT4lCiAgZHBseXI6OnJlbmFtZSgiSGkyMCIgPSAiSGkgMjAiKQpgYGAKCmBgYHtyfQojc3Vic3RyYWN0IFJpc2stRnJlZS1SYXRlCnR3ZW50eWZpdmVfcG9ydGZfcmYgPC0gbXV0YXRlKHR3ZW50eWZpdmVfcG9ydGZfam9pbmVkLCBMbzIwcmYgPSBMbzIwIC0gUkYsIFFudDJyZiA9IFFudDIgLSBSRiwgUW50M3JmID0gUW50MyAtIFJGLCBRbnQ0cmYgPSBRbnQ0IC0gUkYsIEhpMjByZiA9IEhpMjAgLSBSRikKdHdlbnR5Zml2ZV9wb3J0Zl9yZiA8LSB0d2VudHlmaXZlX3BvcnRmX3JmWy0yOi0xMF0KCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CiNzdWJzdHJhY3QgUmlzay1GcmVlLVJhdGUKdHdlbnR5Zml2ZV9wb3J0Zl9yZiA8LSBtdXRhdGUodHdlbnR5Zml2ZV9wb3J0Zl9qb2luZWQsIExvMjByZiA9IExvMjAgLSBSRiwgUW50MnJmID0gUW50MiAtIFJGLCBRbnQzcmYgPSBRbnQzIC0gUkYsIFFudDRyZiA9IFFudDQgLSBSRiwgSGkyMHJmID0gSGkyMCAtIFJGKQp0d2VudHlmaXZlX3BvcnRmX3JmIDwtIHR3ZW50eWZpdmVfcG9ydGZfcmZbLTI6LTEwXQoKCiNDcmVhdGUgWFRTCnR3ZW50eWZpdmVfcG9ydGZfcmZfeHRzIDwtIHR3ZW50eWZpdmVfcG9ydGZfcmYgJT4lCiAgdGtfeHRzKGRhdGVfdmFyID0gZGF0ZSwgc2lsZW50ID0gVFJVRSkKCiNDYWxjdWxhdGUgQmV0YXMgZm9yIGVhY2ggcG9ydGZvbGlvCmJldGFzX3R3ZW50eWZpdmVfcG9ydGYgPC0gQ0FQTS5iZXRhKFJhID0gdHdlbnR5Zml2ZV9wb3J0Zl9yZl94dHMsIFJiID0gbWt0X2ZhY3RvcnNfeHRzWywgMV0sIFJmID0gMCkKCiNFc3RpbWF0ZSBNZWFuIFJldHVybgptZWFuX3R3ZW50eWZpdmVfcG9ydGZfcmZfeHRzIDwtIGFzLmRhdGEuZnJhbWUobGFwcGx5KHR3ZW50eWZpdmVfcG9ydGZfcmZfeHRzLCBGVU49bWVhbikpCgojUGxvdCB0aGUgcmV0dXJuL2JldGEtY29tYmluYXRpb25zCnBsb3QuZGVmYXVsdCh4ID0gYmV0YXNfdHdlbnR5Zml2ZV9wb3J0ZiwgeGxpbT1jKDAsIDIpLAogICAgICAgICAgICAgeSA9IG1lYW5fdHdlbnR5Zml2ZV9wb3J0Zl9yZl94dHMsIHlsaW09YygwLCAxKSwKICAgICAgICAgICAgIHhsYWIgPSAiQmV0YSIsIHlsYWIgPSAiTWVhbiBSZXR1cm4iLAogICAgICAgICAgICAgbWFpbiA9ICJSZXR1cm4vQmV0YS1jb21iaW5hdGlvbnMgMjUiLAogICAgICAgICAgICAgYWJsaW5lKDAsIHlfbWt0KSkKCiNXZSBub3cgZG8gaXQgd2l0aCB0aGUgbWVhbiByZXR1cm4gb2YgZXZlcnkgcG9ydGZvbGlvIGNvbWJpbmVkLi4uCmNvbV9tZWFuX3R3ZW50eWZpdmVfcG9ydGZfcmYgPC0gc3VtKG1lYW5fdHdlbnR5Zml2ZV9wb3J0Zl9yZl94dHMpLzUKIyBhbmQgdGhlIGJldGEKbWVhbl9iZXRhc190d2VudHlmaXZlX3BvcnRmIDwtIHN1bShiZXRhc190d2VudHlmaXZlX3BvcnRmKS81CgpwbG90LmRlZmF1bHQoeCA9IG1lYW5fYmV0YXNfdGVuX3BvcnRmLCB4bGltPWMoMCwgMiksCiAgICAgICAgICAgICB5ID0gY29tX21lYW5fdGVuX3BvcnRmX3JmLCB5bGltPWMoMCwgMSksCiAgICAgICAgICAgICB4bGFiID0gIkJldGEiLCB5bGFiID0gIk1lYW4gUmV0dXJuIiwKICAgICAgICAgICAgIG1haW4gPSAiUmV0dXJuL0JldGEtY29tYmluYXRpb25zIFBvcnRmb2xpbyBTdW1tYXJ5IDI1IiwKICAgICAgICAgICAgIGFibGluZSgwLCB5X21rdCkpCnBsb3QuZGVmYXVsdCh4ID0gbWVhbl9iZXRhc190ZW5fcG9ydGYsIHhsaW09YygwLCAyKSwKICAgICAgICAgICAgIHkgPSBjb21fbWVhbl90ZW5fcG9ydGZfcmYsIHlsaW09YygwLCAxKSwKICAgICAgICAgICAgIHhsYWIgPSAiQmV0YSIsIHlsYWIgPSAiTWVhbiBSZXR1cm4iLAogICAgICAgICAgICAgbWFpbiA9ICJSZXR1cm4vQmV0YS1jb21iaW5hdGlvbnMgUG9ydGZvbGlvIFN1bW1hcnkgMTAiLAogICAgICAgICAgICAgYWJsaW5lKDAsIHlfbWt0KSkKCmBgYAoKCmBgYHtyfQojc3Vic3RyYWN0IFJpc2stRnJlZS1SYXRlCnRlbl9wb3J0Zl9yZiA8LSBtdXRhdGUodGVuX3BvcnRmX2pvaW5lZCwgTG8xMHJmID0gTG8xMCAtIFJGLCBEZWMycmYgPSBEZWMyIC0gUkYsIERlYzNyZiA9IERlYzMgLSBSRiwgRGVjNHJmID0gRGVjNCAtIFJGLCBEZWM1cmYgPSBEZWM1IC1SRiwgRGVjNnJmID0gRGVjNiAtIFJGLCBEZWM3cmYgPSBEZWM3IC0gUkYsIERlYzhyZiA9IERlYzggLSBSRiwgRGU5cmYgPSBEZWM5IC0gUkYsIEhpMTByZiA9IEhpMTAgLSBSRikKdGVuX3BvcnRmX3JmIDwtIHRlbl9wb3J0Zl9yZlstMjotMTVdCgp2aWV3KHRlbl9wb3J0Zl9yZikKdGVuX3BvcnRmX3JmCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CiNDcmVhdGUgWFRTCm1rdF9mYWN0b3JzX3h0cyA8LSB0a194dHMoZGF0YSA9IG1rdF9mYWN0b3JzLCBkYXRlX3ZhciA9IGRhdGUpCnRlbl9wb3J0Zl9yZl94dHMgPC0gdGVuX3BvcnRmX3JmICU+JQogIHRrX3h0cyhkYXRlX3ZhciA9IGRhdGUsIHNpbGVudCA9IFRSVUUpCgpgYGAKYGBge3J9Cj9sbSgpCiNDYWxjdWxhdGUgQmV0YXMgZm9yIGVhY2ggcG9ydGZvbGlvCmJldGFzX3Rlbl9wb3J0Zl9sbSA8LSBsbSh0ZW5fcG9ydGZfcmZfeHRzIH4gbWt0X2ZhY3RvcnNfeHRzWywgMV0pCmJldGFzX3Rlbl9wb3J0Zl9sbQpiZXRhc190ZW5fcG9ydGYgPC0gQ0FQTS5iZXRhKFJhID0gdGVuX3BvcnRmX3JmX3h0cywgUmIgPSBta3RfZmFjdG9yc194dHNbLCAxXSwgUmYgPSAwKQpiZXRhc190ZW5fcG9ydGYKYGBgCkVzdGltYXRlIHRoZSBtZWFuLXJldHVybiBmb3IgZWFjaCBzdG9jayBhbmQgcGxvdCB0aGUgcmV0dXJuL2JldGEtY29tYmluYXRpb25zLgoKYGBge3J9CiNFc3RpbWF0ZSBNZWFuIFJldHVybgptZWFuX3Rlbl9wb3J0Zl9yZl94dHMgPC0gYXMuZGF0YS5mcmFtZShsYXBwbHkodGVuX3BvcnRmX3JmX3h0cywgRlVOPW1lYW4pKQptZWFuX3Rlbl9wb3J0Zl9yZl94dHMKCiNQbG90IHRoZSByZXR1cm4vYmV0YS1jb21iaW5hdGlvbnMKcGxvdC5kZWZhdWx0KHggPSBiZXRhc190ZW5fcG9ydGYsIHhsaW09YygwLCAyKSwKICAgICAgICAgICAgIHkgPSBtZWFuX3Rlbl9wb3J0Zl9yZl94dHMsIHlsaW09YygwLCAxKSwKICAgICAgICAgICAgIHhsYWIgPSAiQmV0YSIsIHlsYWIgPSAiTWVhbiBSZXR1cm4iLAogICAgICAgICAgICAgbWFpbiA9ICJSZXR1cm4vQmV0YS1jb21iaW5hdGlvbnMiKQpgYGAKQ3JlYXRlIHRoZSBzZWN1cml0eSBtYXJrZXQgbGluZSBhbmQgaW5jbHVkZSBpdCBpbiB0aGUgcGxvdCEgV2hhdCBkbyB5b3UgZmluZD8KCmBgYHtyfQptZWFuX21rdCA8LSBhcy5kYXRhLmZyYW1lKGxhcHBseShta3RfZmFjdG9yc194dHNbLCAxXSwgRlVOPW1lYW4pKQp5X21rdCA8LSBtZWFuX21rdFsxLCAxXQpwbG90LmRlZmF1bHQoeCA9IGJldGFzX3Rlbl9wb3J0ZiwgeGxpbT1jKDAsIDIpLAogICAgICAgICAgICAgeSA9IG1lYW5fdGVuX3BvcnRmX3JmX3h0cywgeWxpbT1jKDAsIDEpLAogICAgICAgICAgICAgeGxhYiA9ICJCZXRhIiwgeWxhYiA9ICJNZWFuIFJldHVybiIsCiAgICAgICAgICAgICBtYWluID0gIlJldHVybi9CZXRhLWNvbWJpbmF0aW9ucyIsCiAgICAgICAgICAgICBhYmxpbmUoMCwgeV9ta3QpKQoKCiMKYGBgCihZb3UgY2FuIHNwbGl0IHRoZSBmaWxlIGluIDItMyBkaWZmZXJlbnQgdGltZSBibG9ja3MgYW5kIHNlZSBpZiBzb21ldGhpbmcgY2hhbmdlcykuICogTm93IHdlIGFyZSBkb25lIHdpdGggdGhlIGZpcnN0LXBhc3MgcmVncmVzc2lvbi4qCgpgYGB7cn0KI2xvb2sgZm9yIGZpcnN0IDEwIHllYXJzCnRlbl9wb3J0Zl9yZl8xMHlyc194dHMgPC0gdGVuX3BvcnRmX3JmWzE6MTIwLCBdICU+JQogIHRrX3h0cyhkYXRlX3ZhciA9IGRhdGUsIHNpbGVudCA9IFRSVUUpCmJldGFzX3Rlbl9wb3J0Zl9yZl8xMHlycyA8LSBDQVBNLmJldGEoUmEgPSB0ZW5fcG9ydGZfcmZfMTB5cnNfeHRzLCBSYiA9IG1rdF9mYWN0b3JzX3h0c1sxOjEyMCwgMV0sIFJmID0gMCkKbWVhbl90ZW5fcG9ydGZfcmZfMTB5cnNfeHRzIDwtIGFzLmRhdGEuZnJhbWUobGFwcGx5KHRlbl9wb3J0Zl9yZl8xMHlyc194dHMsIEZVTj1tZWFuKSkKbWVhbl9ta3RfMTB5cnMgPC0gYXMuZGF0YS5mcmFtZShsYXBwbHkobWt0X2ZhY3RvcnNfeHRzWzE6MTIwLCAxXSwgRlVOPW1lYW4pKQp5X21rdF8xMHlycyA8LSBtZWFuX21rdF8xMHlyc1sxLCAxXQpwbG90LmRlZmF1bHQoeCA9IGJldGFzX3Rlbl9wb3J0Zl9yZl8xMHlycywgeGxpbT1jKDAsIDIpLAogICAgICAgICAgICAgeSA9IG1lYW5fdGVuX3BvcnRmX3JmXzEweXJzX3h0cywgeWxpbT1jKDAsIDEpLAogICAgICAgICAgICAgeGxhYiA9ICJCZXRhIiwgeWxhYiA9ICJNZWFuIFJldHVybiIsCiAgICAgICAgICAgICBtYWluID0gIlJldHVybi9CZXRhLWNvbWJpbmF0aW9ucyAxOTY0LTE5NzQiLAogICAgICAgICAgICAgYWJsaW5lKDAsIHlfbWt0XzEweXJzKSkKc3VtbWFyeV9DQVBNX3Rlbl9wb3J0Zl8xMHlycyA8LSAodGFibGUuQ0FQTShSYSA9IHRlbl9wb3J0Zl9yZl94dHNbMToxMjAsIF0sIFJiID0gbWt0X2ZhY3RvcnNfeHRzWzE6MTIwLCAxXSwgUmYgPSAwKVsxOjksIF0pCnN1bW1hcnlfQ0FQTV90ZW5fcG9ydGZfMTB5cnMKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQoKI2xvb2sgZm9yIDIwMDAtMjAxOQp0ZW5fcG9ydGZfcmZfMjAwMF94dHMgPC0gdGVuX3BvcnRmX3JmWzQzMzo2NzIsIF0gJT4lCiAgdGtfeHRzKGRhdGVfdmFyID0gZGF0ZSwgc2lsZW50ID0gVFJVRSkKYmV0YXNfdGVuX3BvcnRmX3JmXzIwMDAgPC0gQ0FQTS5iZXRhKFJhID0gdGVuX3BvcnRmX3JmXzIwMDBfeHRzLCBSYiA9IG1rdF9mYWN0b3JzX3h0c1s0MzM6NjcyLCAxXSwgUmYgPSAwKQptZWFuX3Rlbl9wb3J0Zl9yZl8yMDAwX3h0cyA8LSBsYXBwbHkodGVuX3BvcnRmX3JmXzIwMDBfeHRzLCBGVU49bWVhbikKbWVhbl90ZW5fcG9ydGZfcmZfMjAwMF94dHMgPC0gYXMuZGF0YS5mcmFtZShtZWFuX3Rlbl9wb3J0Zl9yZl8yMDAwX3h0cykKbWVhbl9ta3RfMjAwMCA8LSBsYXBwbHkobWt0X2ZhY3RvcnNfeHRzWzQzMzo2NzIsIDFdLCBGVU49bWVhbikKbWVhbl9ta3RfMjAwMCA8LSBhcy5kYXRhLmZyYW1lKG1lYW5fbWt0XzIwMDApCnlfbWt0XzIwMDAgPC0gbWVhbl9ta3RfMjAwMFsxLCAxXQpwbG90LmRlZmF1bHQoeCA9IGJldGFzX3Rlbl9wb3J0Zl9yZl8yMDAwLCB4bGltPWMoMCwgMiksCiAgICAgICAgICAgICB5ID0gbWVhbl90ZW5fcG9ydGZfcmZfMjAwMF94dHMsIHlsaW09YygwLCAxKSwKICAgICAgICAgICAgIHhsYWIgPSAiQmV0YSIsIHlsYWIgPSAiTWVhbiBSZXR1cm4iLAogICAgICAgICAgICAgbWFpbiA9ICJSZXR1cm4vQmV0YS1jb21iaW5hdGlvbnMgMjAwMC0yMDE5IiwKICAgICAgICAgICAgIGFibGluZSgwLCB5X21rdF8yMDAwKSkKc3VtbWFyeV9DQVBNX3Rlbl9wb3J0Zl8yMDAwIDwtICh0YWJsZS5DQVBNKFJhID0gdGVuX3BvcnRmX3JmX3h0c1s0MzM6NjcyLCBdLCBSYiA9IG1rdF9mYWN0b3JzX3h0c1s0MzM6NjcyLCAxXSwgUmYgPSAwKVsxOjksIF0pCnN1bW1hcnlfQ0FQTV90ZW5fcG9ydGZfMjAwMAoKcGxvdC5kZWZhdWx0KHggPSBiZXRhc190ZW5fcG9ydGYsIHhsaW09YygwLCAyKSwKICAgICAgICAgICAgIHkgPSBtZWFuX3Rlbl9wb3J0Zl9yZl94dHMsIHlsaW09YygwLCAxKSwKICAgICAgICAgICAgIHhsYWIgPSAiQmV0YSIsIHlsYWIgPSAiTWVhbiBSZXR1cm4iLAogICAgICAgICAgICAgbWFpbiA9ICJSZXR1cm4vQmV0YS1jb21iaW5hdGlvbnMgMTk2NC0yMDE5IiwKICAgICAgICAgICAgIGFibGluZSgwLCB5X21rdCkpCnN1bW1hcnlfQ0FQTV90ZW5fcG9ydGYKCgpgYGAKCgpiKQlJbiB0aGUgc2Vjb25kLXBhc3MgcmVncmVzc2lvbiB3ZSBub3cgcmVncmVzcyB0aGUgYXZlcmFnZSBzdG9jayByZXR1cm5zIG9uIHRoZSBiZXRhcyBlc3RpbWF0ZWQgYmVmb3JlLiBXaGF0IGRvIHlvdSBmaW5kIGluIHRoZSBjb2VmZmljaWVudHMgYW5kIGRvZXMgdGhpcyBjb250cmFkaWN0IHRoZSBDQVBNPyBUcnkgZGlmZmVyZW50IHRpbWUgcGVyaW9kcyBhZ2FpbiBhbmQgc2VlIHdoYXQgeW91IGZpbmQuIChhbGwgb2YgdGhlIGludGVycHJldGF0aW9ucyBhcmUgaW4gQktNIHBwLjQxNmYpLiAKClRoZXJlIGFyZSBhIG51bWJlciBvZiByZWFzb25zIHdlIGV4cGVjdCBtaWdodCB0aGUgQ0FQTSB0bwpmYWlsOgoxLiBJbXBlcmZlY3QgbWVhc3VyZXMgb2YgdGhlIG1hcmtldCBwb3J0Zm9saW8KMi4gQmV0YSBpcyBhbiBpbmNvbXBsZXRlIG1lYXN1cmUgb2YgcmlzawozLiBUYXggZWZmZWN0cwo0LiBOb24gLSBub3JtYWxpdHkgb2YgcmV0dXJucwo1LiBObyByaXNrbGVzcyBhc3NldAo2LiBEaXZlcmdlbnQgYm9ycm93aW5nIGFuZCBsZW5kaW5nIHJhdGVzCgpjKQlOb3cgZG8gdGhlIGV4dGVuZGVkIHNlY29uZCBwYXNzIHJlZ3Jlc3Npb24gKHJlZ3Jlc3Mgb24gYmV0YXMgYW5kIHJlc2lkdWFsLXNkcyB0aGF0IHlvdSBjYW4gZXh0cmFjdCBmcm9tIHRoZSByZWdyZXNzaW9uKSBhbmQgc2VlIHdoYXQgeW91IGZpbmQgZm9yIGRpZmZlcmVudCBwZXJpb2RzLiBJbnRlcnByZXQgYWNjb3JkaW5nIHRvIGNvbmNlcHQgY2hlY2sgMTMuMi4gT25lIG9mIHRoZSAobWFueSkgcHJvYmxlbXMgb2YgdGhlIENBUE0gY2FuIGJlIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHJlc2lkdWFsIHZhcmlhbmNlcyBhbmQgYmV0YXMuIENhbGN1bGF0ZSBhbmQgaW50ZXJwcmV0LgoKYGBge3J9CiNMb29rIGF0IGEpIC0+IFdlIG5vdyBkbyBpdCB3aXRoIHRoZSBtZWFuIHJldHVybiBvZiBldmVyeSBwb3J0Zm9saW8gY29tYmluZWQuLi4gCgojMTk2NC0yMDE5CmNvbV9tZWFuX3Rlbl9wb3J0Zl9yZiA8LSBzdW0obWVhbl90ZW5fcG9ydGZfcmZfeHRzKS8xMAptZWFuX2JldGFzX3Rlbl9wb3J0ZiA8LSBzdW0oYmV0YXNfdGVuX3BvcnRmKS8xMApwbG90LmRlZmF1bHQoeCA9IG1lYW5fYmV0YXNfdGVuX3BvcnRmLCB4bGltPWMoMCwgMiksCiAgICAgICAgICAgICB5ID0gY29tX21lYW5fdGVuX3BvcnRmX3JmLCB5bGltPWMoMCwgMiksCiAgICAgICAgICAgICB4bGFiID0gIkJldGEiLCB5bGFiID0gIk1lYW4gUmV0dXJuIiwKICAgICAgICAgICAgIG1haW4gPSAiUmV0dXJuL0JldGEtY29tYmluYXRpb25zIDEwIFBvcnRmb2xpb3MgMTk2NC0yMDE5IiwKICAgICAgICAgICAgIGFibGluZSgwLCB5X21rdCkpCgoKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0KCiMxOTY0LTE5NzQKY29tX21lYW5fdGVuX3BvcnRmX3JmXzEweXJzIDwtIHN1bShtZWFuX3Rlbl9wb3J0Zl9yZl8xMHlyc194dHMpLzEwCm1lYW5fYmV0YXNfdGVuX3BvcnRmXzEweXJzIDwtIHN1bShiZXRhc190ZW5fcG9ydGZfcmZfMTB5cnMpLzEwCnBsb3QuZGVmYXVsdCh4ID0gbWVhbl9iZXRhc190ZW5fcG9ydGZfMTB5cnMsIHhsaW09YygwLCAyKSwKICAgICAgICAgICAgIHkgPSBjb21fbWVhbl90ZW5fcG9ydGZfcmZfMTB5cnMsIHlsaW09YygwLCAyKSwKICAgICAgICAgICAgIHhsYWIgPSAiQmV0YSIsIHlsYWIgPSAiTWVhbiBSZXR1cm4iLAogICAgICAgICAgICAgbWFpbiA9ICJSZXR1cm4vQmV0YS1jb21iaW5hdGlvbnMgMTAgUG9ydGZvbGlvcyAxOTY0LTE5NzQiLAogICAgICAgICAgICAgYWJsaW5lKDAsIHlfbWt0XzEweXJzKSkKCiMyMDAwLTIwMTkKY29tX21lYW5fdGVuX3BvcnRmX3JmXzIwMDAgPC0gc3VtKG1lYW5fdGVuX3BvcnRmX3JmXzIwMDBfeHRzKS8xMAptZWFuX2JldGFzX3Rlbl9wb3J0Zl8yMDAwIDwtIHN1bShiZXRhc190ZW5fcG9ydGZfcmZfMjAwMCkvMTAKcGxvdC5kZWZhdWx0KHggPSBtZWFuX2JldGFzX3Rlbl9wb3J0Zl8yMDAwLCB4bGltPWMoMCwgMiksCiAgICAgICAgICAgICB5ID0gY29tX21lYW5fdGVuX3BvcnRmX3JmXzIwMDAsIHlsaW09YygwLCAyKSwKICAgICAgICAgICAgIHhsYWIgPSAiQmV0YSIsIHlsYWIgPSAiTWVhbiBSZXR1cm4iLAogICAgICAgICAgICAgbWFpbiA9ICJSZXR1cm4vQmV0YS1jb21iaW5hdGlvbnMgMTAgUG9ydGZvbGlvcyAyMDAwLTIwMTkiLAogICAgICAgICAgICAgYWJsaW5lKDAsIHlfbWt0XzIwMDApKQoKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0KCiNTTUwtRnVuY3Rpb24KY2FsY19yZXNpZHVhbCA8LSBmdW5jdGlvbih4KSB7eSA8LSB5X21rdCp4fQpjYWxjX3Jlc2lkdWFsXzEweXJzIDwtIGZ1bmN0aW9uKHgpIHt5IDwtIHlfbWt0XzEweXJzKnh9CmNhbGNfcmVzaWR1YWxfMjAwMCA8LSBmdW5jdGlvbih4KSB7eSA8LSB5X21rdF8yMDAwKnh9CnJlc2lkdWFsXzE5NjRfMjAxOSA8LSBhcy5kYXRhLmZyYW1lKChjb21fbWVhbl90ZW5fcG9ydGZfcmYgLSBjYWxjX3Jlc2lkdWFsKG1lYW5fYmV0YXNfdGVuX3BvcnRmKSleMikKcmVzaWR1YWxfMTk2NF8xOTc0IDwtIGFzLmRhdGEuZnJhbWUoKGNvbV9tZWFuX3Rlbl9wb3J0Zl9yZl8xMHlycyAtIGNhbGNfcmVzaWR1YWxfMTB5cnMobWVhbl9iZXRhc190ZW5fcG9ydGZfMTB5cnMpKV4yKQpyZXNpZHVhbF8yMDAwXzIwMTkgPC0gYXMuZGF0YS5mcmFtZSgoY29tX21lYW5fdGVuX3BvcnRmX3JmXzIwMDAgLSBjYWxjX3Jlc2lkdWFsXzIwMDAobWVhbl9iZXRhc190ZW5fcG9ydGZfMjAwMCkpXjIpCmpvaW5lZF9yZXNpZHVhbHMgPC0gbWVyZ2UocmVzaWR1YWxfMTk2NF8yMDE4WzEsIDFdLCByZXNpZHVhbF8xOTY0XzE5NzRbMSwgMV0pCmpvaW5lZF9yZXNpZHVhbHMgPC0gbWVyZ2Uoam9pbmVkX3Jlc2lkdWFscywgcmVzaWR1YWxfMjAwMF8yMDE4KQpSZXNpZHVhbHNfZGlmZmVyZW50X3RpbWVwZXJpb2RzIDwtIGpvaW5lZF9yZXNpZHVhbHMgJT4lIAogIGRwbHlyOjpyZW5hbWUoIlJlc2lkdWFsIDIwMDAtMjAxOSIgPSAiKGNvbV9tZWFuX3Rlbl9wb3J0Zl9yZl8yMDAwIC0gY2FsY19yZXNpZHVhbF8yMDAwKG1lYW5fYmV0YXNfdGVuX3BvcnRmXzIwMDApKV4yIikgJT4lIGRwbHlyOjpyZW5hbWUoIlJlc2lkdWFsIDE5NjQtMjAwOCIgPSAieCIpICU+JSBkcGx5cjo6cmVuYW1lKCJSZXNpZHVhbCAxOTY0LTE5NzQiID0gInkiKQpSZXNpZHVhbHNfZGlmZmVyZW50X3RpbWVwZXJpb2RzCmBgYAoKCmQpCVRyeSBhZ2FpbiB3aXRoIDI1IHBvcnRmb2xpb3Mgc29ydGVkIG9uIHNpemUgYW5kIGJldGEuIFdoYXQgZG8geW91IGZpbmQ/IElzIHRoYXQgaW50ZXJlc3Rpbmc/IAoKYGBge3J9CiNqb2luIGRhdGEKdHdlbnR5Zml2ZV9wb3J0ZiA8LSBwb3J0Zl9ta3RfYmV0YVsxOjY3MiwgLWMoNzoxNildCnR3ZW50eWZpdmVfcG9ydGZfam9pbmVkIDwtIGxlZnRfam9pbihta3RfZmFjdG9ycywgdHdlbnR5Zml2ZV9wb3J0ZikKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0KCnR3ZW50eWZpdmVfcG9ydGZfam9pbmVkIDwtIHR3ZW50eWZpdmVfcG9ydGZfam9pbmVkIDwtIHR3ZW50eWZpdmVfcG9ydGZfam9pbmVkJT4lCiAgZHBseXI6OnJlbmFtZSgiTG8yMCIgPSAiTG8gMjAiKSAlPiUKICBkcGx5cjo6cmVuYW1lKCJRbnQyIiA9ICJRbnQgMiIpICU+JQogIGRwbHlyOjpyZW5hbWUoIlFudDMiID0gIlFudCAzIikgJT4lCiAgZHBseXI6OnJlbmFtZSgiUW50NCIgPSAiUW50IDQiKSAlPiUKICBkcGx5cjo6cmVuYW1lKCJIaTIwIiA9ICJIaSAyMCIpCmBgYAoKYGBge3J9CiNzdWJzdHJhY3QgUmlzay1GcmVlLVJhdGUKdHdlbnR5Zml2ZV9wb3J0Zl9yZiA8LSBtdXRhdGUodHdlbnR5Zml2ZV9wb3J0Zl9qb2luZWQsIExvMjByZiA9IExvMjAgLSBSRiwgUW50MnJmID0gUW50MiAtIFJGLCBRbnQzcmYgPSBRbnQzIC0gUkYsIFFudDRyZiA9IFFudDQgLSBSRiwgSGkyMHJmID0gSGkyMCAtIFJGKQp0d2VudHlmaXZlX3BvcnRmX3JmIDwtIHR3ZW50eWZpdmVfcG9ydGZfcmZbLTI6LTEwXQoKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0KI3N1YnN0cmFjdCBSaXNrLUZyZWUtUmF0ZQp0d2VudHlmaXZlX3BvcnRmX3JmIDwtIG11dGF0ZSh0d2VudHlmaXZlX3BvcnRmX2pvaW5lZCwgTG8yMHJmID0gTG8yMCAtIFJGLCBRbnQycmYgPSBRbnQyIC0gUkYsIFFudDNyZiA9IFFudDMgLSBSRiwgUW50NHJmID0gUW50NCAtIFJGLCBIaTIwcmYgPSBIaTIwIC0gUkYpCnR3ZW50eWZpdmVfcG9ydGZfcmYgPC0gdHdlbnR5Zml2ZV9wb3J0Zl9yZlstMjotMTBdCgoKI0NyZWF0ZSBYVFMKdHdlbnR5Zml2ZV9wb3J0Zl9yZl94dHMgPC0gdHdlbnR5Zml2ZV9wb3J0Zl9yZiAlPiUKICB0a194dHMoZGF0ZV92YXIgPSBkYXRlLCBzaWxlbnQgPSBUUlVFKQoKI0NhbGN1bGF0ZSBCZXRhcyBmb3IgZWFjaCBwb3J0Zm9saW8KYmV0YXNfdHdlbnR5Zml2ZV9wb3J0ZiA8LSBDQVBNLmJldGEoUmEgPSB0d2VudHlmaXZlX3BvcnRmX3JmX3h0cywgUmIgPSBta3RfZmFjdG9yc194dHNbLCAxXSwgUmYgPSAwKQoKI0VzdGltYXRlIE1lYW4gUmV0dXJuCm1lYW5fdHdlbnR5Zml2ZV9wb3J0Zl9yZl94dHMgPC0gYXMuZGF0YS5mcmFtZShsYXBwbHkodHdlbnR5Zml2ZV9wb3J0Zl9yZl94dHMsIEZVTj1tZWFuKSkKCiNQbG90IHRoZSByZXR1cm4vYmV0YS1jb21iaW5hdGlvbnMKcGxvdC5kZWZhdWx0KHggPSBiZXRhc190d2VudHlmaXZlX3BvcnRmLCB4bGltPWMoMCwgMiksCiAgICAgICAgICAgICB5ID0gbWVhbl90d2VudHlmaXZlX3BvcnRmX3JmX3h0cywgeWxpbT1jKDAsIDEpLAogICAgICAgICAgICAgeGxhYiA9ICJCZXRhIiwgeWxhYiA9ICJNZWFuIFJldHVybiIsCiAgICAgICAgICAgICBtYWluID0gIlJldHVybi9CZXRhLWNvbWJpbmF0aW9ucyAyNSIsCiAgICAgICAgICAgICBhYmxpbmUoMCwgeV9ta3QpKQoKI1dlIG5vdyBkbyBpdCB3aXRoIHRoZSBtZWFuIHJldHVybiBvZiBldmVyeSBwb3J0Zm9saW8gY29tYmluZWQuLi4KY29tX21lYW5fdHdlbnR5Zml2ZV9wb3J0Zl9yZiA8LSBzdW0obWVhbl90d2VudHlmaXZlX3BvcnRmX3JmX3h0cykvNQojIGFuZCB0aGUgYmV0YQptZWFuX2JldGFzX3R3ZW50eWZpdmVfcG9ydGYgPC0gc3VtKGJldGFzX3R3ZW50eWZpdmVfcG9ydGYpLzUKCnBsb3QuZGVmYXVsdCh4ID0gbWVhbl9iZXRhc190ZW5fcG9ydGYsIHhsaW09YygwLCAyKSwKICAgICAgICAgICAgIHkgPSBjb21fbWVhbl90ZW5fcG9ydGZfcmYsIHlsaW09YygwLCAxKSwKICAgICAgICAgICAgIHhsYWIgPSAiQmV0YSIsIHlsYWIgPSAiTWVhbiBSZXR1cm4iLAogICAgICAgICAgICAgbWFpbiA9ICJSZXR1cm4vQmV0YS1jb21iaW5hdGlvbnMgUG9ydGZvbGlvIFN1bW1hcnkgMjUiLAogICAgICAgICAgICAgYWJsaW5lKDAsIHlfbWt0KSkKcGxvdC5kZWZhdWx0KHggPSBtZWFuX2JldGFzX3Rlbl9wb3J0ZiwgeGxpbT1jKDAsIDIpLAogICAgICAgICAgICAgeSA9IGNvbV9tZWFuX3Rlbl9wb3J0Zl9yZiwgeWxpbT1jKDAsIDEpLAogICAgICAgICAgICAgeGxhYiA9ICJCZXRhIiwgeWxhYiA9ICJNZWFuIFJldHVybiIsCiAgICAgICAgICAgICBtYWluID0gIlJldHVybi9CZXRhLWNvbWJpbmF0aW9ucyBQb3J0Zm9saW8gU3VtbWFyeSAxMCIsCiAgICAgICAgICAgICBhYmxpbmUoMCwgeV9ta3QpKQoKYGBgCgoKCioqVGhlIHB1cnBvc2Ugb2YgdGhlIGZ1cnRoZXIgYXNzaWdubWVudHMgaXMgbGVzcyBwcm9ncmFtbWluZy1yZWxhdGVkICh5b3UgY2FuIGNvcHkgbW9zdCBvZiB0aGUgY29kZSksIGJ1dCB0byByZWNlaXZlIGEgcG9zaXRpdmUgZ3JhZGUgSSB3YW50IHlvdSB0byBkaWcgaW50byB0aGUgcmVmZXJlbmNlZCBsaXRlcmF0dXJlIGFuZCBiZSBhYmxlIHRvIGV4cGxhaW4gX2V2ZXJ5dGhpbmdfIHRoYXQgeW91IGRvIHZlcnkgZGV0YWlsZWQgaW4gdGhlIHRleHQgYW5kIHlvdXIgcHJlc2VudGF0aW9uICh3aGF0IGRvIHlvdSBkbywgd2hhdCBpcyB0aGUgcmVzdWx0IGFuZCBob3cgZG8geW91IGludGVwcmV0IHRoZSByZXN1bHQpLiBBZnRlciBkb2luZyB0aGlzIC0gZ2l2ZW4gdGhlIGRhdGEgLSB5b3Ugc2hvdWxkIGJlIHBlcmZlY3RseSBhYmxlIHRvIGVzdGltYXRlL2ludGVycHJldCBhbnkgdHlwZSBvZiBmYWN0b3IgbW9kZWwuKioKICAKIyMgRXhlcmNpc2UgMzogU3RhdGlzdGljYWwgRmFjdG9yIE1vZGVscwoKYGBge3J9CmxpYnJhcnkodGltZXRrKQpTUDUwMCA8LSB0cV9pbmRleCgiU1A1MDAiKQpOQVNEQVEgPC0gdHFfZXhjaGFuZ2UoIk5BU0RBUSIpCk5ZU0UgPC0gdHFfZXhjaGFuZ2UoIk5ZU0UiKSAKc3RvY2tzLnNlbGVjdGlvbiA8LSBTUDUwMCAlPiUgCiAgaW5uZXJfam9pbihyYmluZChOWVNFLE5BU0RBUSkgJT4lIHNlbGVjdChzeW1ib2wsbGFzdC5zYWxlLnByaWNlLG1hcmtldC5jYXAsaXBvLnllYXIpLGJ5PWMoInN5bWJvbCIpKSAlPiUKICBmaWx0ZXIoaXBvLnllYXI8MjAwMCYhaXMubmEobWFya2V0LmNhcCkpICU+JSAKICBhcnJhbmdlKGRlc2Mod2VpZ2h0KSkgJT4lIAogIHNsaWNlKDE6MTApCnN0b2Nrcy5zZWxlY3Rpb24KYGBgCgpUaGVzZSBhcmUgdGhlIHJldHVybnMgb2YgdGhlIHNlbGVjdGVkIHN0b2Nrcy4KCmBgYHtyfQpzdG9ja3MucmV0dXJucyA8LSBzdG9ja3Muc2VsZWN0aW9uJHN5bWJvbCAlPiUKICAgIHRxX2dldChnZXQgID0gInN0b2NrLnByaWNlcyIsCiAgICAgICAgICAgZnJvbSA9ICIyMDAwLTAxLTAxIiwKICAgICAgICAgICB0byAgID0gIjIwMTktMTItMzEiKSAlPiUKICAgIGdyb3VwX2J5KHN5bWJvbCkgJT4lCiAgICB0cV90cmFuc211dGUoc2VsZWN0ICAgICA9IGFkanVzdGVkLCAKICAgICAgICAgICAgICAgICBtdXRhdGVfZnVuID0gcGVyaW9kUmV0dXJuLCAKICAgICAgICAgICAgICAgICBwZXJpb2QgICAgID0gIm1vbnRobHkiKQpzdG9ja3MucmV0dXJucwpgYGAKClRoZXNlIGFyZSB0aGUgc3RvY2tzIHJldHVybiBpbiB0aGUgeHRzIGZvcm1hdCBhbmQgYWxzbyBpbiBhIHdpZGUgZm9ybWF0CmBgYGB7cn0Kc3RvY2tzLnJldHVybnMueHRzIDwtIHN0b2Nrcy5yZXR1cm5zJT4lCiAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQoIHNlbGVjdCA9IGMoc3ltYm9sLGRhdGUsIG1vbnRobHkucmV0dXJucykpICU+JQogICAgICAgICAgICAgICAgICAgICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHN5bWJvbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IG1vbnRobHkucmV0dXJucykgJT4lIAogICAgICAgICAgICAgICAgICAgICAgdGtfeHRzKGRhdGVfdmFyID0gZGF0ZSwgc2lsZW50ID0gVFJVRSkKY29sbmFtZXMoc3RvY2tzLnJldHVybnMueHRzKQpgYGAKCiMjIyBGaXQgYSBzdGF0aXN0aWNhbCBmYWN0b3IgbW9kZWwgZml0U2ZtCgpQcmluY2lwYWwgQ29tcG9uZW50IEFuYWx5c2lzIChQQ0EpOiB1c2VzIHRoZSBlaWdlbiBkZWNvbXBvc2l0aW9uIG9mIHRoZSBjb3ZhcmlhbmNlIG1hdHJpeCBvZiBhc3NldCByZXR1cm5zIHRvIGZpbmQgdGhlIGZpcnN0IEsgcHJpbmNpcGFsIGNvbXBvbmVudHMgdGhhdCBleHBsYWluIHRoZSBsYXJnZXN0IHBvcnRpb24gb2YgdGhlIHNhbXBsZSBjb3ZhcmlhbmNlIG1hdHJpeCByZXR1cm5zLiBGYWN0b3IgbG9hZGluZyBhcmUgdGhlbiBlc3RpbWF0ZWQgdXNpbmcgdGltZSBzZXJpZXMgcmVncmVzc2lvbi4gRm9jdG9yIGFuYWx5c2lzIGludm9sdmVzIG1heGltdW0gbGlrZWxpaG9vZCBvcHRpbWl6YXRpb24gdG8gZXN0aW1hdGUgdGhlIGZhY3RvciBsb2FkaW5ncyBhbmQgdGhlIHJlc2lkdWFsIGNvdmFyaW5jZSBtYXRyaXgsIGNvbnN0cnVjdGluZyB0aGUgZmFjdG9yIHJlYWxpemF0aW9uIGFuZCBjaG9vc2luZyBhIHJvdGF0aW9uIG9mIHRoZSBjb29yZGluYXRlIHN5c3RlbSBmb3IgYSBtb3JlIG1lZWFuaW5nZnVsIGludGVycHJldGlvbiBvZiBmYWN0b3JzCgp1c2VkIHdoZW4gVD5OClQ6IE51bWJlciBvZiBvYnNlcnZhdGlvbnMKTjogTnVtYmVyIG9mIGFzc2V0cwoKaWYgTj5UIHRoZW4gQXltcHRvdGljIFByaW5jaXBhbCBDb21wb25lbnQgQW5hbHlzaXMgKEFQQ0EpCgojIyMjIFByaW5jaXBhbCBDb21wb25lbnQgQW5hbHlzaXMKRml0dGluZyBhIHN0YXRpc3RpY2FsIGZhY3RvciBtb2RlbCB3aXRoIHR3byBwcmluY2lwYWwgY29tcG9uZW50cyAoaz0yKQpgYGB7cn0KZml0LnBjYSA8LSBmaXRTZm0oc3RvY2tzLnJldHVybnMueHRzLCBrPTIpCmZpdC5wY2EgCmBgYApTY3JlZW5wbG90IG9mIGVpZ2VudmFsdWVzCkFuIGVpZ2VudmVjdG9yIG9mIGEgbGluZWFyIHRyYW5zZm9ybWF0aW9uIGlzIGEgbm9uemVybyB2ZWN0b3IgdGhhdCBjaGFuZ2VzIGJ5IGEgc2NhbGFyIGZhY3RvciB3aGVuIHRoYXQgbGluZWFyIHRyYW5zZm9ybWF0aW9uIGlzIGFwcGxpZWQgdG8gaXQuIEVpZ2VudmFsdWVzIGFuZCBlaWdlbnZlY3RvcnMgYWxsb3cgdXMgdG8gInJlZHVjZSIgYSBsaW5lYXIgb3BlcmF0aW9uIHRvIHNlcGFyYXRlLCBzaW1wbGVyLCBwcm9ibGVtcy4KYGBge3J9CnBsb3QoZml0LnBjYSwgd2hpY2g9MSwgZWlnLm1heCA9IDAuOSkKCmBgYAoKRmlyc3QgcHJpbmNpcGFsIGNvbXBvbmVudCBleHBsYWlucyBhYm91dCA0OCUgb2YgdG90YWwgdmFyaWFuY2UuIFRoZSBmaXJzdCB0d28gY29tcG9uZW50cyBleHBsYWluIGFib3V0IDYxJSBvZiB0b3RhbCB2YXJpYW5jZS4KCk5vdyBwbG90dGluZyB0aGUgZXN0aW1hdGVkIGZhY3RvciByZXR1cm5zCmBgYHtyfQpwbG90KGZpdC5wY2EsIHdoaWNoPTIpCmBgYAoKRXN0aW1hdGVkIGZhY3RvciBsb2FkaW5ncyBmb3IgYWxsIGFzc2V0cwpGYWN0b3IgbG9hZGluZyBpcyB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgZm9yIHRoZSB2YXJpYWJsZSBhbmQgZmFjdG9yLgpgYGB7cn0KCnBsb3QoZml0LnBjYSwgd2hpY2g9MywgYS5zdWI9MToxMCkKCmBgYApGaXJzdCBmYWN0b3IgaGFzIGFsbCBwb3NpdGl2ZSBsb2FkaW5ncywgd2hlcmVhcyB0aGUgc2Vjb25kIGZhY3RvciBoYXMgYm90aCBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgbG9hZGluZ3MuCgoKYGBge3J9CnQoZml0LnBjYSRtaW1pYykKCnBsb3QoZml0LnBjYSwgd2hpY2g9MTIsIG4udG9wPTMpCmBgYApUaGlzIGZpZ3VyZSBkaXNwbGF5cyB0aGUgdG9wIHRocmVlIGFzc2V0cyB3aXRoIHRoZSBsYXJnZXN0IGFuZCBzbWFsbGVzIHdlaWdodHMgaW4gZWFjaCBmYWN0b3IgbWltaWNraW5nIHBvcnRmb2xpby4gRm9yIHRoZSBmaXJzdCBmYWN0b3IsIE5WSURBLCBBbWF6b25lIGFuZCBBZG9iZSBoYXZlIHRoZSBoaWdoZXN0IHdlaWdodHMgYW5kIEFtZ2VuLCBVUFMgYW5kIE1pY3Jvc29mdCBoYXZlIHRoZSBsb3dlc3Qgd2VpZ2h0cy4gU2luY2UgYWxsIHdlaWdodHMgYXJlIHBvc2l0aXZlIHRoaXMgbWlnaHQgYmUgY29uc3RydWVkIGFzIGEgbWFya2V0LXdpZGUgZmFjdG9yLiBGb3IgdGhlIHNlY29uZCBmYWN0b3IsIEFtYXpvbiwgUXVhbGNvbSBhbmQgQ2lzY28gaGF2ZSB0aGUgaGlnaGVzdCB3ZWlnaHRzIGFuZCBOVklEQSwgQXBwbGUgYW5kIEFkb2JlIGhhdmUgdGhlIGxvd2VzdCB3ZWlnaHRzLgoKTm93IHBsb3R0aW5nIHRoZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhc3NldHMgd2l0aCB0aGUgdG9wIDMgbGFyZ2VzdCBhbmQgc21hbGxlc3QgcG9zaXRpb25zIGluIHRoZSBGLjEgZmFjdG9yIG1pbWlja2luZyBwb3J0Zm9saW8KCmBgYHtyfQpwbG90KGZpdC5wY2EsIHdoaWNoPTEzLCBmLnN1Yj0xLCBuLnRvcD0zKQpgYGAKSGVyZSB3ZSBjYW4gc2VlIHRoZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhc3NldHMgd2l0aCB0b3AgMyBsYXJnZXN0IGFuZCBzbWFsbGVzdCB3ZWlnaHQgaW4gdGhlIGZhY3RvciBtaW1pY2tpbmcgcG9ydGZvbGlvIGZvciB0aGUgZmlyc3QgcHJpbmNpcGFsIGNvbXBvbmVudC4gQ29ycmVsYXRpb25zIGFyZSB2ZXJ5IGRpZmZlcmVudC4KCgpgYGB7cn0KcGxvdChmaXQucGNhLCB3aGljaD0xMywgZi5zdWI9Miwgbi50b3A9MykKYGBgCkhlcmUgd2UgY2FuIHNlZSB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gYXNzZXRzIHdpdGggdG9wIDMgbGFyZ2VzdCBhbmQgc21hbGxlc3Qgd2VpZ2h0IGluIHRoZSBmYWN0b3IgbWltaWNraW5nIHBvcnRmb2xpbyBmb3IgdGhlIGZpcnN0IHByaW5jaXBhbCBjb21wb25lbnQuIFByZXR0eSBoaWdoIGNvcnJlbGF0aW9ucyBvdmVyYWxsLgoKCgoKCiMjIyMgUzMgZ2VuZXJpYyBtZXRob2RzCmFsbCBlc3RpbWFkZWQgY29lZmZpY2llbnRzIGZyb20gUENBIGluY2x1ZGluZyBpbnRlcmNlcHQKYGBge3J9CmNvZWYoZml0LnBjYSkKYGBgCgpjb21wYXJlIHJldHVybnMgZGF0YSB3aXRoIGZpdHRlZCBhbmQgcmVzaWR1YWwgdmFsdWVzIGZvciBBQVBMOiBmaXQucGNhCmBgYHtyfQpBQVBMLnRzIDwtIG1lcmdlKGZpdC5wY2EkZGF0YVssMV0sIGZpdHRlZChmaXQucGNhKVssMV0sIHJlc2lkdWFscyhmaXQucGNhKVssMV0pCgpjb2xuYW1lcyhBQVBMLnRzKSA8LSBjKCJBQVBMLnJldHVybiIsICJBQVBMLmZpdHRlZCIsICJBQVBMLnJlc2lkdWFsIikKCnRhaWwoQUFQTC50cykKYGBgCgpmaXR0ZWQoKTogcmV0dXJucyBhbiB4dHMgZGF0YSBvYmplY3Qgb2YgdGhlIGNvbXBvbmVudCBvZiBhc3NldCByZXR1cm5zIGV4cGxhaW5lZCBieSB0aGUgZmFjdG9yIG1vZGVsCgpyZXNpZHVhbHMoKTogcmV0dXJucyB4dHMgZGF0YSBvYmplY3Qgd2l0aCB0aGUgY29tcG9uZW50IG9mIGFzc2V0IHJldHVybnMgbm90IGV4cGxhaW5lZCBieSB0aGUgZmFjdG9yIG1vZGVsCgpTdW1tYXJ5IGZvciBmaXQucGNhIHdpdGggSEFDIHN0YW5kYXJkIGVycm9ycyAoYWxsb3dzIGZvciBoZXRlcm9za2VkYXN0aWNpdHkgYW5kIGF1dG9jb3JyZWxhdGlvbiBjb25zaXN0ZW50IGVzdGltYXRlcyBhbmQgc3RhbmRhcmQgZXJyb3JzKQpgYGB7cn0Kc3VtLnBjYSA8LSBzdW1tYXJ5KGZpdC5wY2EsIHNlLnR5cGU9IkhBQyIsIG4udG9wPTMpCgpzdW0ucGNhJHN1bS5saXN0W1sxXV0KYGBgCmZhY3RvciBtaW1pY2tpbmcgcG9ydGZvbGlvIHdlaWdodHMKYGBge3J9CnN1bS5wY2EkbWltaWMuc3VtCmBgYAoKIyMjIEZhY3RvciBNb2RlbCBDb3ZhcmlhbmNlIGFuZCBSaXNrIERlY29tcG9zaXRpb24KCiMjIyMgRmFjdG9yIG1vZGVsIGNvdmFyaWFuY2UKCmBgYHtyfQpPbWVnYSA8LSBmbUNvdihmaXQucGNhKQojIHJldHVybiBjb3JyZWxhdGlvbiBwbG90IGZvciBhbGwgYXNzZXRzCnBsb3QoZml0LnBjYSwgd2hpY2g9OCwgYS5zdWI9MToxMCkKYGBgCgojIyMjIFN0YW5kYXJkIGRldmlhdGlvbiBkZWNvbXBvc2l0aW9uCmBgYHtyfQpkZWNvbXAgPC0gZm1TZERlY29tcChmaXQucGNhKQoKI2dldCB0aGUgZmFjdG9yIG1vZGVsIHN0YW5kYXJkIGRldmlhdGlvbiBmb3IgYWxsIGFzc2V0cwpkZWNvbXAkU2QuZm0KCiNnZXQgdGhlIGNvbXBvbmVudCBjb250cmlidXRpb24gdG8gU2QKaGVhZChkZWNvbXAkY1NkKQoKI3Bsb3R0aW5nCnBsb3QoZml0LnBjYSwgd2hpY2g9OSwgZi5zdWI9MToyLCBhLnN1Yj0xOjEwKQpgYGAKCiMjIyMgVmFsdWUtYXQtUmlzayBkZWNvbXBvc2l0aW9uCmBgYHtyfQpkZWNvbXAxIDwtIGZtVmFSRGVjb21wKGZpdC5wY2EpCgojZmFjdG9yIG1vZGVsIFZhbHVlLWF0LVJpc2sKaGVhZChkZWNvbXAxJFZhUi5mbSkKCiNNYXJnaW5hbCBmYWN0b3IgY29udHJpYnV0aW9ucyB0byBWQVIKaGVhZChkZWNvbXAxJG1WYVIpCgojIHBsb3R0aW5nCnBsb3QoZml0LnBjYSwgd2hpY2g9MTEsIGYuc3ViPTE6MiwgYS5zdWI9MToxMCkKYGBgCgoKIyMjI0V4cGVjdGVkIFNob3JmYWxsIGRlY29tcG9zaXRpb24KYGBge3J9CmRlY29tcDIgPC0gZm1Fc0RlY29tcChmaXQucGNhKQojIGZhY3RvciBtb2RlbCBFeHBlY3RlZCBTaG9ydGZhbGwKaGVhZChkZWNvbXAyJEVTLmZtKQoKIyBwZXJjZW50YWdlIGNvbXBvbmVudCBjb250cmlidXRpb24gdG8gRVMKaGVhZChkZWNvbXAyJHBjRVMpCgojIHBsb3R0aW5nCnBsb3QoZml0LnBjYSwgd2hpY2ggPSAxMCwgZi5zdWI9MToyLCBhLnN1Yj0xOjEwKQpgYGAKCiMjIEV4ZXJjaXNlIDQ6IFRpbWVzZXJpZXMgRmFjdG9yIE1vZGVscwoKRm9sbG93IHRoZSBmaWxlIFt0c2ZtVmlnbmV0dGUucGRmXShodHRwczovL2dpdGh1Yi5jb20vYnJhdmVyb2NrL0ZhY3RvckFuYWx5dGljcy9ibG9iL21hc3Rlci92aWduZXR0ZXMvdHNmbVZpZ25ldHRlLnBkZikgYW5kIGludGVycHJldCB5b3VyIHJlc3VsdHMuCgojIyMgVGhlb3JpZQpJbiBhIHRpbWUgc2VyaWVzIG9yIG1hY3JvZWNvbm9taWMgZmFjdG9yIG1vZGVsLCBvYnNlcnZhYmxlIGVjb25vbWljIHRpbWUgc2VyaWVzIHN1Y2ggYXMgaW5kdXN0cmlhbCBwcm9kdWN0aW9uIGdyb3d0aCByYXRlLCBpbnRlcmVzdCByYXRlcywgbWFya2V0IHJldHVybnMgYW5kIGluZmxhdGlvbiBhcmUgdXNlZCBhcyBjb21tb24gZmFjdG9ycyB0aGF0IGNvbnRyaWJ1dGUgdG8gYXNzZXQgcmV0dXJucy4gCi0gRm9yIGV4YW1wbGUsIHRoZSBmYW1vdXMgKnNpbmdsZSBpbmRleCBtb2RlbCBieSBTaGFycGUqICgxOTY0KSB1c2VzIHRoZSBtYXJrZXQgZXhjZXNzIHJldHVybiBhcyB0aGUgKmNvbW1vbiBmYWN0b3IqIChjYXB0dXJlcyBlY29ub215LXdpZGUgb3IgbWFya2V0IHJpc2spIGZvciBhbGwgYXNzZXRzIGFuZCB0aGUgKnVuZXhwbGFpbmVkIHJldHVybnMgaW4gdGhlIGVycm9yIHRlcm0qIHJlcHJlc2VudHMgdGhlICpub24tbWFya2V0IGZpcm0gc3BlY2lmaWMgcmlzayouIAotIE9uIHRoZSBvdGhlciBoYW5kLCAqQ2hlbiBldCBhbC4gKDE5ODYpIHVzZXMgYSBtdWx0aS1mYWN0b3IgbW9kZWwqIHRvIGZpbmQgdGhhdCBzdXJwcmlzZSBpbmZsYXRpb24sIHRoZSBzcHJlYWQgYmV0d2VlbiBsb25nIGFuZCBzaG9ydC10ZXJtIGludGVyZXN0IHJhdGVzIGFuZCBiZXR3ZWVuIGhpZ2ggYW5kIGxvdyBncmFkZSBib25kcyBhcmUgKnNpZ25pZmljYW50bHkgcHJpY2VkKiwgd2hpbGUgdGhlIG1hcmtldCBwb3J0Zm9saW8sIGFnZ3JlZ2F0ZSBjb25zdW1wdGlvbiByaXNrIGFuZCBvaWwgcHJpY2UgcmlzayBhcmUgKm5vdCBwcmljZWQgc2VwYXJhdGVseSouCgpgYGB7cn0KCmxpYnJhcnkoRmFjdG9yQW5hbHl0aWNzKQoKYGBgCgoKYGBge3J9CgojIFRoZSBmb2xsb3dpbmcgZXhhbXBsZXMgcHJpbWFyaWx5IHVzZSB0aGUgbWFuYWdlcnMgZGF0YXNldCBmcm9tIHRoZSBQZXJmb3JtYW5jZUFuYWx5dGljcyBwYWNrYWdlLiAKIyBJdOKAmXMgYW4gInh0cyIgZGF0YSBvYmplY3Qgd2l0aDoKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0gMTMyIG9ic2VydmF0aW9ucyBvZiBtb250aGx5IHJldHVybnMKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0gb24gMTAgdmFyaWFibGVzOgojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0gc2l4IGh5cG90aGV0aWNhbCBhc3NldCBtYW5hZ2VycywgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLSAxeCBkaGVjIHJldHVybnMgKExvbmctU2hvcnQgRXF1aXR5IGhlZGdlIGZ1bmQgaW5kZXgpCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLSAxeCBzcDUwMCByZXR1cm5zCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLSBVUyB0cmVhc3VyeSBib25kcyAxMCB5ZWFycyAod2lsbCBzZXJ2ZSBhcyBleHBsYW5hdG9yeSBmYWN0b3JzKQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0gVVMgdHJlYXN1cnkgYmlsbHMgMyBtb250aHMgKGNhbiBiZSBjb25zaWRlcmVkIGFzIHRoZSByaXNrIGZyZWUgcmF0ZSkKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0gdGhlcmUgYXJlIHNvbWUgIm5vdCBhdmFpbGFibGUiIG9ic2VydmF0aW9ucyAoc3RhcnQgZGF5ISkKCmRhdGEobWFuYWdlcnMpCgojIFdlIHdhbnQgdG8gc2VlIHRoZSBtYW5hZ2VycyBuYW1lcwpjb2xuYW1lcyhtYW5hZ2VycykKCiMgYW5kIHdlIHdhbnQgdG8gc2VlIGZyb20gd2hlbiB0byB3aGVuIHRoZSBkYXRhIGlzIGF2YWlsYWJsZSAKZmlyc3QobWFuYWdlcnMpCmxhc3QobWFuYWdlcnMpCgpgYGAKCmBgYHtyfQoKIyB0aGUgSGFtMS1IYW02IGFyZSB0aGUgYXNzZXQgcmV0dXJucyB3ZSB3YW50IHRvIGV4cGxhaW4gLS0+IHkgaW4gb3VyIG1vZGVsCmFzc2V0Lm5hbWVzIDwtIGNvbG5hbWVzKG1hbmFnZXJzWywxOjZdKSAKCiMgdGhlIGVkaGVjLCBzcDUwMCAmIFVTIFRyZWFzdXJ5IHRoZXkgYXJlIHRoZSBleHBsYW5hdG9yeSBvbmVzIC0tPiB4IGluIG91ciBtb2RlbApmYWN0b3IubmFtZXMgPC0gY29sbmFtZXMobWFuYWdlcnNbLDc6OV0pIAoKIyBUeXBpY2FsbHksIGZhY3RvciBtb2RlbHMgYXJlIGZpdCB1c2luZyBleGNlc3MgcmV0dXJucy4gSWYgdGhlIGFzc2V0IGFuZCBmYWN0b3IgcmV0dXJucyBhcmUgbm90IGluIGV4Y2VzcyByZXR1cm4gZm9ybSwgInJmLm5hbWUiIGNhbiBiZSBzcGVjaWZpZWQgdG8gY29udmVydCByZXR1cm5zIGludG8gZXhjZXNzIHJldHVybnMuIApyZi5uYW1lIDwtICJVUy4zbS5UUiIKCiMgU2ltaWxhcmx5LCBtYXJrZXQgcmV0dXJucyBjYW4gYmUgc3BlY2lmaWVkIHZpYSAibWt0Lm5hbWUiIHRvIGFkZCBtYXJrZXQtdGltaW5nIGZhY3RvcnMgdG8gdGhlIGZhY3RvciBtb2RlbC4KbWt0Lm5hbWUgPC0gIlNQNTAwLlRSIiAKCmBgYAoKIyMjIExldOKAmXMgdGFrZSBhIGxvb2sgYXQgdGhlIGFyZ3VtZW50cyBmb3IgKmZpdFRzZm0qLgoKVGhlIGRlZmF1bHQgbW9kZWwgZml0dGluZyBtZXRob2QgaXMgKkxTIHJlZ3Jlc3Npb24qIGFuZCB0aGUgZGVmYXVsdCB2YXJpYWJsZSBzZWxlY3Rpb24gbWV0aG9kCmlzICJub25lIiAodGhhdCBpcywgYWxsIGZhY3RvcnMgYXJlIGluY2x1ZGVkIGluIHRoZSBtb2RlbCkuIApUaGUgZGlmZmVyZW50IG1vZGVsIGZpdHRpbmcgb3B0aW9ucyBhcmU6IAoxLiBsZWFzdCBzcXVhcmVzIChMUyksIAoyLiBkaXNjb3VudGVkIGxlYXN0IHNxdWFyZXMgKERMUykgYW5kCjMuIHJvYnVzdCByZWdyZXNzaW9uIGZpdHRpbmcgKFJvYnVzdCkKCgpBbmQgdmFyaWFibGVzZWxlY3Rpb24gb3B0aW9ucyBhcmU6CjEuICJzdGVwd2lzZSIsIAoyLiAic3Vic2V0cyIgYW5kIAozLiAibGFycyIKClRoZSBkZWZhdWx0IGZvciByZi5uYW1lIGFuZCBta3QubmFtZSBhcmUgTlVMTC4gSWYgcmYubmFtZSBpcyBub3Qgc3BlY2lmaWVkIGJ5IHRoZSB1c2VyLApwZXJoYXBzIGJlY2F1c2UgdGhlIGRhdGEgaXMgYWxyZWFkeSBpbiBleGNlc3MgcmV0dXJuIGZvcm0sIHRoZW4gbm8gcmlzay1mcmVlIHJhdGUgYWRqdXN0bWVudCBpcwptYWRlLiBTaW1pbGFybHksIGlmIG1rdC5uYW1lIGlzIG5vdCBzcGVjaWZpZWQsIG1hcmtldC10aW1pbmcgZmFjdG9ycyBhcmUgbm90IGFkZGVkIHRvIHRoZSBtb2RlbC4KQWxsIG90aGVyIG9wdGlvbmFsIGNvbnRyb2wgcGFyYW1ldGVycyBwYXNzZWQgdGhyb3VnaCB0aGUgZWxsaXBzaXMgYXJlIHByb2Nlc3NlZCBhbmQgYXNzaW1pbGF0ZWQKaW50ZXJuYWxseSBieSBmaXRUc2ZtLmNvbnRyb2wuCgpgYGB7cn0KCiMgVGhlIHNlcmllcyBoYXZlIHVuZXF1YWwgaGlzdG9yaWVzIGluIHRoaXMgc2FtcGxlIGFuZCDigJxmaXRUc2Zt4oCcIHJlbW92ZXMgYXNzZXQtd2lzZSBpbmNvbXBsZXRlIGNhc2VzIChhc3NldOKAmXMgcmV0dXJuIGRhdGEgY29tYmluZWQgd2l0aCByZXNwZWN0aXZlIGZhY3RvcnPigJkgcmV0dXJuIGRhdGEpIGJlZm9yZSBmaXR0aW5nIGEgZmFjdG9yIG1vZGVsLgphcmdzKGZpdFRzZm0pCgpgYGAKCmBgYHtyfQoKIyBTaW5nbGUgSW5kZXggTW9kZWwgdXNpbmcgU1A1MDAgCmZpdC5zaW5nbGVJbmRleCA8LSBmaXRUc2ZtKGFzc2V0Lm5hbWVzPWFzc2V0Lm5hbWVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjdG9yLm5hbWVzPSJTUDUwMC5UUiIsICAgI3NwZWNmaWMgZmFjdG9yIQogICAgICAgICAgICAgICAgICAgICAgICAgICByZi5uYW1lPSJVUy4zbS5UUiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPW1hbmFnZXJzKQoKIyBmaXR0ZWQgb2JqZWN0IGZyb20gdGhlIHRpbWUtc2VyaWVzIExTIHJlZ3Jlc3Npb24gb2YgYXNzZXQgcmV0dXJucyBvbiBlc3RpbWF0ZWQgZmFjdG9ycy4KZml0LnNpbmdsZUluZGV4JGFzc2V0LmZpdAoKIyBzcGVjaWZpY3MgdmFsdWVzCmZpdC5zaW5nbGVJbmRleCRhbHBoYQpmaXQuc2luZ2xlSW5kZXgkYmV0YQoKIyBJbnRlcnByZXRhdGlvbjoKIyBpZiB0aGUgbWFya2V0IHJldHVybiByaXNlcyAxJSwgdGhlbiB0aGUgcmV0dXJuIG9mIEhhbTEgcmlzZXMgMCwzOSUKYGBgCgpgYGB7cn0KIyBSLXNxdWFyZWQgaXMgYSBzdGF0aXN0aWNhbCBtZWFzdXJlIG9mIGhvdyBjbG9zZSB0aGUgZGF0YSBhcmUgdG8gdGhlIGZpdHRlZCByZWdyZXNzaW9uIGxpbmUuIEl0IGlzIGFsc28ga25vd24gYXMgdGhlIGNvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb24sIG9yIHRoZSBjb2VmZmljaWVudCBvZiBtdWx0aXBsZSBkZXRlcm1pbmF0aW9uIGZvciBtdWx0aXBsZSByZWdyZXNzaW9uLiBUaGUgZGVmaW5pdGlvbiBvZiBSLXNxdWFyZWQgaXMgZmFpcmx5IHN0cmFpZ2h0LWZvcndhcmQ7IGl0IGlzIHRoZSBwZXJjZW50YWdlIG9mIHRoZSByZXNwb25zZSB2YXJpYWJsZSB2YXJpYXRpb24gdGhhdCBpcyBleHBsYWluZWQgYnkgYSBsaW5lYXIgbW9kZWwKIyBSLXNxdWFyZWQgaXMgYWx3YXlzIGJldHdlZW4gMCBhbmQgMTAwJToKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwJSBpbmRpY2F0ZXMgdGhhdCB0aGUgbW9kZWwgZXhwbGFpbnMgbm9uZSBvZiB0aGUgdmFyaWFiaWxpdHkgb2YgdGhlIHJlc3BvbnNlIGRhdGEgYXJvdW5kIGl0cyBtZWFuLgojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwMCUgaW5kaWNhdGVzIHRoYXQgdGhlIG1vZGVsIGV4cGxhaW5zIGFsbCB0aGUgdmFyaWFiaWxpdHkgb2YgdGhlIHJlc3BvbnNlIGRhdGEgYXJvdW5kIGl0cyBtZWFuCgoKZml0LnNpbmdsZUluZGV4JHIyCgoKIyBJbnRlcnByZXRhdGlvbjoKIyBSLXNxdWFyZWQ6IDEgd291bGQgYmUgMTAwJSAtIGxpbmVhciBmdW5jdGlvbiBtYXRjaGVzIHBlcmZlY3RseSB3aXRoIHRoZSBkYXRhIC0tPiBoZXJlIHdlIGhhdmUgbG93IFItc3F1YXJlZApgYGAKCmBgYHtyfQojIFRoZSByZXNpZHVhbHMgc2hvdyBob3cgZmFyIHRoZSBkYXRhIGZhbGwgZnJvbSB0aGUgcmVncmVzc2lvbiBsaW5lIGFuZCBhc3Nlc3MgaG93IHdlbGwgdGhlIGxpbmUgZGVzY3JpYmVzIHRoZSBkYXRhLgpmaXQuc2luZ2xlSW5kZXgkcmVzaWQuc2QKCiMgSW50ZXJwcmV0YXRpb246CiMgaGVyZSB3ZSBoYXZlIGxvdyByZXNpZHVhbHMKCmBgYAoKYGBge3J9CgpjbGFzcyhmaXQuc2luZ2xlSW5kZXgpCiMgdGltZSBzZXJpZXMgZmFjdG9yIG1vZGVsCmBgYAoKYGBge3J9CgpuYW1lcyhmaXQuc2luZ2xlSW5kZXgpCgpgYGAKCk92ZXJ2aWV3IG9mIHRoZSBzaW5nbGUgZmFjdG9yIGxpbmVhciBmaXRzIGZvciB0aGUgYXNzZXRzLiAKYGBge3J9CgpmaXQuc2luZ2xlSW5kZXgKIyBJbnRlcnByZXRhdGlvbjoKIyBIb3cgZ29vZCBkb2VzIHRoZSBzaW5nbGUgaW5kZXggbW9kZWwgZml0cyB0byB0aGUgZGF0YT8KIyBIYW0xIGVxdWFscyBhIGxpbmVhciByZWdyZXNzaW9uIHRoZSBtb3N0IC0tPiBmaXRzIHRoZSBiZXN0IC0tPiBSLXNxdWFyZWQgaXMgdGhlIGhpZ2hlc3QKIyBIYW01IGRvZXMgbm90IHJlYWxseSBmaXQgdG8gdGhpcyBtb2RlIC0tPiBhbGZhIGFuZCBSLXNxdWFyZWQgdmFsdWVzCgpgYGAKCmBgYHtyfQoKcGxvdChmaXQuc2luZ2xlSW5kZXgsIHdoaWNoPTEyLCBmLnN1Yj0xKQoKYGBgCgojIyMgSGVucmlrc3Nvbi1NZXJ0b24ncyAtIG1hcmtldCB0aW1pbmcgbW9kZWxzCk1hcmtldCB0aW1pbmcgYWNjb3VudHMgZm9yIHRoZSBwcmljZSBtb3ZlbWVudCBvZiB0aGUgZ2VuZXJhbCBzdG9jayBtYXJrZXQgcmVsYXRpdmUgdG8gZml4ZWQgaW5jb21lIHNlY3VyaXRpZXMuClRoaXMgaW5jbHVkZXMgdGhlIGRvd24ubWFya2V0IGZhY3RvciAtLT4gbWF4KDAsIFJmLVJtKQpUbyB0ZXN0IG1hcmtldCB0aW1pbmcgYWJpbGl0eSwgdGhpcyBmYWN0b3IgY2FuIGJlIGFkZGVkIHRvIHRoZSBzaW5nbGUgaW5kZXggbW9kZWwgYXMgc2hvd24gYmVsb3cuIFRoZSBjb2VmZmljaWVudCBvZiB0aGlzIGRvd24tbWFya2V0IGZhY3RvciBjYW4gYmUKaW50ZXJwcmV0ZWQgYXMgdGhlIG51bWJlciBvZiAiZnJlZSIgcHV0IG9wdGlvbnMgb24gdGhlIG1hcmtldCBwcm92aWRlZCBieSB0aGUgbWFuYWdlcuKAmXMgbWFya2V0dGltaW5ncyBraWxscy4gVGhhdCBpcywgYSBuZWdhdGl2ZSB2YWx1ZSBmb3IgdGhlIHJlZ3Jlc3Npb24gZXN0aW1hdGUgd291bGQgaW1wbHkgYSBuZWdhdGl2ZSB2YWx1ZSBmb3IgbWFya2V0IHRpbWluZyBhYmlsaXR5IG9mIHRoZSBtYW5hZ2VyLgoKYGBge3J9CgojIEhlbnJpa3Nzb24tTWVydG9uJ3MgbWFya2V0IHRpbWluZyBtb2RlbApmaXQubWt0VGltaW5nIDwtIGZpdFRzZm1NVChhc3NldC5uYW1lcz1hc3NldC5uYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1rdC5uYW1lPSJTUDUwMC5UUiIsICMgc3BlY2lmeSB3aGljaCBvZiB0aGUgY29sdW1ucyBpbiBkYXRhIGNvcnJlc3BvbmRzIHRvIHRoZSBtYXJrZXQgcmV0dXJucyB1c2luZyBhcmd1bWVudCBta3QubmFtZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgcmYubmFtZT0iVVMuM20uVFIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1tYW5hZ2VycykKCnQoZml0Lm1rdFRpbWluZyRiZXRhKQoKIyBJbnRlcnByZXRhdGlvbjoKIyBUZXN0IG1hcmtldCB0aW1pbmcgYWJpbGl0eToKIyB3aGVuIHRoZSB2YWx1ZSBvZiBkb3duLm1hcmtldCBpcyBuZWdhdGl2ZSwgdGhlIGFiaWxpdHkgb2YgbWFya2V0IHRpbWluZyBvZiBhIG1hbmFnZXIgaXMgbG93IC0tPiBub3QgZXZlbiB0aGVyZQojIHNvIHRoZSBtYW5hZ2VyIDIgaGFzIHRoZSBiZXN0IGFiaWxpdHkgb2YgbWFya2V0IHRpbWluZyBhbmQgYWZ0ZXIgdGhhdCBtYW5hZ2VyIDYgLS0+IHRoZXkgaGF2ZSB0aGUgaGlnaHRlcyBpbnRlcmNlcHQgKHdoaWNoIHJldHVybiB0aGV5IHdpbGwgbWFrZSB3aGVuIHRoZSBtYXJrZXQgbWFrZXMgbm8gcmV0dXJuKQoKYGBgCgoKYGBge3J9CgpmaXQubWt0VGltaW5nJHIyCiMgSW50ZXJwcmV0YXRpb246CiMgUl4yIC0+IGhvdyBnb29kIHRoZSBkYXRhIGZpdHMgdG8gdGhlIG1vZGVsLiAKIyBhbGwgdmFsdWUgaGF2ZSBpbmNyZWFzZWQgc2xpZ2h0bHkKCmBgYAoKYGBge3J9CgpmaXQubWt0VGltaW5nJHJlc2lkLnNkCiMgSW50ZXJwcmV0YXRpb246CiMgdm9sYXRpbGl0eTogaG93IG11Y2ggaXQganVtcHMgYXJvdW5kIHJlbGF0aXZlIHRvIGl0cyByZWxhdGlvbnNoaXAgdG8gYW4gaW5kZXgoc3A1MDApCiMgcmlzazogdGhlIGhpZ2hlciB0aGUgd29yc2UKCiMjI2ZpdCBtZXRob2RzCiNscyA9IGxlYXN0IHNxdWFyZXMKI2RscyA9IGRpc2NvdW50ZWQgbGVhc3Qgc3F1YXJlcyAod2VpZ2h0ZXMgbGVhc3Qgc3F1YXJlcykKI3JvYnVzdCA9IGlzIGdvb2QgZm9yIGRhdGEgd2l0aCBvdXRsaWVycwpgYGAKCmBgYHtyfQojY29tcGFyaXNvbiAKZml0Lm1rdFRpbWluZwpmaXQuc2luZ2xlSW5kZXgKYGBgCgoKRml0cyBNb2RlbDoKClRoZSBkaWZmZXJlbnQgbW9kZWwgZml0dGluZyBvcHRpb25zIGFyZTogCgoxLiAob3JkaW5hcnkpIGxlYXN0IHNxdWFyZXMgKG9scyAvIExTKSAtLT4gRGVmYXVsdCBtb2RlIQoyLiBkaXNjb3VudGVkIGxlYXN0IHNxdWFyZXMgKERMUykgYW5kCjMuIHJvYnVzdCByZWdyZXNzaW9uIGZpdHRpbmcgKFJvYnVzdCkKCiMjIyBPcmRpbmFyeSBsZWFzdCBzcXVhcmVzICgib2xzIikKCmBgYHtyfQojICBUaGUgbmV4dCBleGFtcGxlIHBlcmZvcm1zIExTIHJlZ3Jlc3Npb24gdXNpbmcgYWxsIDMgYXZhaWxhYmxlIGZhY3RvcnMgaW4gdGhlIGRhdGFzZXQuCmZpdC5vbHMgPC0gZml0VHNmbShhc3NldC5uYW1lcz1hc3NldC5uYW1lcywgCiAgICAgICAgICAgICAgICAgICBmYWN0b3IubmFtZXM9ZmFjdG9yLm5hbWVzLCAjIGFsbCAzIGF2YWlsYWJsZSBmYWN0b3JzOiB0aGUgZWRoZWMsIHNwNTAwICYgVVMuMTBZLlRSL1VTIFRyZWFzdXJ5CiAgICAgICAgICAgICAgICAgICByZi5uYW1lPSJVUy4zbS5UUiIsIAogICAgICAgICAgICAgICAgICAgZGF0YT1tYW5hZ2VycykgCgoKZml0Lm9scyRiZXRhCiMgSW50ZXJwcmV0YXRpb246CiMgbm93IHdlIGNvbnNpZGVyIGFsbCBmYWN0b3JzIChleHBsYW5hdG9yeSBmYWN0b3JzKQoKIyBTZW5zaXRpdml0eTogCiMgd2hlbiB0aGUgcmV0dXJuIG9mIGVkaGVjIHJpc2VzIDElIC0tPiBIYW0yIHJpc2VzIDAsMTU0NyUKIyB3aGVuIHNwNTAwIHJldHVybiByaXNlcyAxJSwgSGFtMiBkZWNyZWFzZXMgYnkgMCwxOTUlCiMgd2hlbiBVUy4xMFkuVFIgcmV0dXJuIHJpc2VzIDElLCBIYW0yIGRlY3JlYXNlcyBieSAwLDA1MDQlCmBgYAoKYGBge3J9CgpmaXQub2xzJHIyCiMgSW50ZXJwcmV0YXRpb246CiMgaG93IGdvb2QgZG9lcyB0aGUgZGF0YSBmaXQgdG8gdGhlIG1vZGVsCiMgSGFtMyBmaXRzIHRoZSBiZXN0IHdpdGggNjYlCgpgYGAKCmBgYHtyfQoKZml0Lm9scyRyZXNpZC5zZAojIEludGVycHJldGF0aW9uOgojIFZvbGF0aWxpdHkKIyBIb3cgbXVjaCB0aGV5IGp1bXAgYXJvdW5kIC0tPiBtb3N0IEhhbTQgMC4wNDI3CmBgYAoKCiMjIyBPdGhlciBvcHRpb25zIHJvYnVzdCByZWdyZXNzaW9uICgiUm9idXN0IikuIApgYGB7cn0KCmZpdC5yb2J1c3QgPC0gZml0VHNmbShhc3NldC5uYW1lcz1hc3NldC5uYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICBmYWN0b3IubmFtZXM9ZmFjdG9yLm5hbWVzLCAKICAgICAgICAgICAgICAgICAgICAgIHJmLm5hbWU9IlVTLjNtLlRSIiwgCiAgICAgICAgICAgICAgICAgICAgICBkYXRhPW1hbmFnZXJzLCAKICAgICAgICAgICAgICAgICAgICAgIGZpdC5tZXRob2Q9IlJvYnVzdCIpICMgTWV0aG9kICJSb2J1c3QiIQpmaXQucm9idXN0JGJldGEKIyBJbnRlcnByZXRhdGlvbjoKCmBgYAoKYGBge3J9CgpmaXQucm9idXN0JHIyCiMgSW50ZXJwcmV0YXRpb246CiMgUi1zcXVhcmVkIGlzIG5vdyBsb3dlciBmb3IgZWFjaAojIG1heWJlIHRoZXkgYWxsIGhhZCBvdXRsaWVycwoKYGBgCgoKYGBge3J9CgpmaXQucm9idXN0JHJlc2lkLnNkCiMgSW50ZXJwcmV0YXRpb246CgpgYGAKCmBgYHtyfQoKcGFyKG1mcm93PWMoMiwxKSkKcGxvdChmaXQub2xzLCBwbG90LnNpbmdsZT1UUlVFLCB3aGljaD0xLCBhc3NldC5uYW1lPSJIQU0zIikKbXRleHQoIkxTIiwgc2lkZT0zKQpgYGAKCmBgYHtyfQpwbG90KGZpdC5yb2J1c3QsIHBsb3Quc2luZ2xlPVRSVUUsIHdoaWNoPTEsIGFzc2V0Lm5hbWU9IkhBTTMiKQptdGV4dCgiUm9idXN0Iiwgc2lkZT0zKQoKCiMgSW50ZXJwcmV0YXRpb246CiMgdm9sYXRpbGl0eSBpcyBzbWFsbGVyIHdoZW4gdXNpbmcgdGhlIHJvYnVzdCBmaXR0aW5nIG1ldGhvZAojIyMgdmFyaWFibGUgc2VsZWN0aW9uCgojIGxhcnMgaXMgYSBnb29kIHZhcmlhYmxlIHRvIGFkZAojIGxlYXN0IGFuZ2xlIHJlZ3Jlc3Npb24KIyBpdCBpcyBnb29kIHdoZW4geW91IGFyZSBhZnJhaWQgb2Ygb3ZlcmZpdHRpbmcgKHRoYXQgeW91IGFkanVzdCB5b3VyIG1vZGVsIHRvbyBtdWNoKQojIHdoZW4geW91IGhhdmUgaGlnaC1kaW1lbnNpb25hbCBkYXRhIChsb3RzIG9mIGV4cGxhbmF0b3J5IGZhY3RvcnMpCgpgYGAKCmBgYHtyfQoKcGFyKG1mcm93PWMoMSwyKSkgCnBsb3QoZml0Lm9scywgd2hpY2g9NSwgeGxpbT1jKDAsMC4wNDUpLCBzdWI9IkxTIikgCnBsb3QoZml0LnJvYnVzdCwgd2hpY2g9NSwgeGxpbT1jKDAsMC4wNDUpLCBzdWI9IlJvYnVzdCIpCgpgYGAKClRob3VnaCB0aGUgUi1zcXVhcmVkIHZhbHVlcyBpbXByb3ZlZCBieSBhZGRpbmcgbW9yZSBmYWN0b3JzIGluIGZpdC5vbHMgKGNvbXBhcmVkIHRvIHRoZSBzaW5nbGUgaW5kZXggbW9kZWwpCgojIyMgVmFyaWFibGUgU2VsZWN0aW9uCk9uZSBtaWdodCBwcmVmZXIgdG8gZW1wbG95IHZhcmlhYmxlIHNlbGVjdGlvbiBtZXRob2RzIHN1Y2ggYXMgInN0ZXB3aXNlIiwgInN1YnNldHMiIG9yICJsYXJzIiB0byBhdm9pZCBvdmVyLWZpdHRpbmcuIFRoZSBtZXRob2QgY2FuIGJlIHNlbGVjdGVkIHZpYSB0aGUgdmFyaWFibGUuc2VsZWN0aW9uIGFyZ3VtZW50LiBUaGUgZGVmYXVsdCAibm9uZSIsIHVzZXMgYWxsIHRoZSBmYWN0b3JzIGFuZCBwZXJmb3JtcyBubyB2YXJpYWJsZSBzZWxlY3Rpb246CgotIFNwZWNpZnlpbmcgKiJzdGVwd2lzZSIqIHNlbGVjdHMgdHJhZGl0aW9uYWwgc3RlcHdpc2UgTFMgb3Igcm9idXN0IHJlZ3Jlc3Npb24gdXNpbmcgc3RlcCBvciBzdGVwLmxtUm9iIHJlc3BlY3RpdmVseS4gU3RhcnRpbmcgZnJvbSB0aGUgZ2l2ZW4gaW5pdGlhbCBzZXQgb2YgZmFjdG9ycywgZmFjdG9ycyBhcmUgYWRkZWQgKG9yIHN1YnRyYWN0ZWQpIG9ubHkgaWYgdGhlIHJlZ3Jlc3Npb24gZml0IGltcHJvdmVzLgotIFNwZWNpZnlpbmcgKiJzdWJzZXRzIiogZW5hYmxlcyBzdWJzZXRzIHNlbGVjdGlvbiB1c2luZyByZWdzdWJzZXRzLiBUaGUgYmVzdCBwZXJmb3JtaW5nIHN1YnNldCBvZiBhbnkgZ2l2ZW4gc2l6ZSBvciB3aXRoaW4gYSByYW5nZSBvZiBzdWJzZXQgc2l6ZXMgaXMgY2hvc2VuLiBEaWZmZXJlbnQgbWV0aG9kcyBzdWNoIGFzIGV4aGF1c3RpdmUgc2VhcmNoIChkZWZhdWx0KSwgZm9yd2FyZCBvciBiYWNrd2FyZCBzdGVwd2lzZSwgb3Igc2VxdWVudGlhbCByZXBsYWNlbWVudCBjYW4gYmUgZW1wbG95ZWQuCi0gRmluYWxseSwgKiJsYXJzIiogY29ycmVzcG9uZHMgdG8gbGVhc3QgYW5nbGUgcmVncmVzc2lvbiB1c2luZyBsYXJzIHdpdGggdmFyaWFudHMgImxhc3NvIiAoZGVmYXVsdCksICJsYXIiLCAiZm9yd2FyZC5zdGFnZXdpc2UiIG9yICJzdGVwd2lzZSIuCgojIyMjIExBUlMgPSBsZWFzdCBhbmdsZSByZWdyZXNzaW9uIAoKYGBge3J9CgpmaXQubGFycyA8LSBmaXRUc2ZtKGFzc2V0Lm5hbWVzPWFzc2V0Lm5hbWVzLCAKICAgICAgICAgICAgICAgICAgICBmYWN0b3IubmFtZXM9ZmFjdG9yLm5hbWVzLCAKICAgICAgICAgICAgICAgICAgICBkYXRhPW1hbmFnZXJzLCAKICAgICAgICAgICAgICAgICAgICByZi5uYW1lPSJVUy4zbS5UUiIsIAogICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLnNlbGVjdGlvbj0ibGFycyIpIAoKZml0LmxhcnMKIyBJbnRlcnByZXRhdGlvbjoKIyBTdWJzZXQgLS0+IHRoZSBiZXN0IHBlcmZvcm1pbmcgc3Vic2V0IHdpdGhpbiBhIHJhbmdlIG9mIHN1YnNldCBzaXplcyBpcyBjaG9zZW4KCmBgYAoKYGBge3J9CgpmaXQuc3ViIDwtIGZpdFRzZm0oYXNzZXQubmFtZXM9YXNzZXQubmFtZXMsIAogICAgICAgICAgICAgICAgICAgZmFjdG9yLm5hbWVzPWZhY3Rvci5uYW1lcywgCiAgICAgICAgICAgICAgICAgICBkYXRhPW1hbmFnZXJzLCAKICAgICAgICAgICAgICAgICAgIHJmLm5hbWU9IlVTLjNtLlRSIiwgCiAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5zZWxlY3Rpb249InN1YnNldHMiLCAKICAgICAgICAgICAgICAgICAgIG52bWluPTIsIG52bWF4PTIpIAoKZml0LnN1YiAKIyBIZXJlLCB0aGUgYmVzdCBzdWJzZXQgb2Ygc2l6ZSAyIGZvciBlYWNoIGFzc2V0IGlzIGNob3NlbiBieSBzcGVjaWZ5aW5nIG52bWluID0gbnZtYXggPSAyLiBOb3RlIHRoYXQgd2hlbiBudm1pbiA8IG52bWF4LCB0aGUgYmVzdCBzdWJzZXQgaXMgY2hvc2VuIGZyb20gYSByYW5nZSBvZiBzdWJzZXQgc2l6ZXMgW252bWluLCBudm1heF0uIERlZmF1bHQgaXMgbnZtaW4gPSAxLgoKIyBJbnRlcnByZXRhdGlvbjoKIyB3ZSBzZWUgYWxsIHRvZ2V0aGVyCiMgaW50ZXJjZXB0cyA9IGFscGhhCiMgd2hlcmUgd2Ugc2VlIHRoZSBpbmRpY2VzIC0tPiBiZXRhcwoKYGBgCgpgYGB7cn0KCnBsb3QoZml0LnN1Yiwgd2hpY2g9MiwgZi5zdWI9MTozKQoKYGBgCgpgYGB7cn0KCnBsb3QoZml0LmxhcnMsIHdoaWNoPTIsIGYuc3ViPTE6MykKCmBgYAojIyMgQmlnIEludGVycHJldGF0aW9uCkNvbXBhcmluZyB0aGUgKmNvZWZmaWNpZW50cyogYW5kICpSLXNxdWFyZWQgdmFsdWVzKiBmcm9tIHRoZSB0d28gbW9kZWxzLCB3ZSBmaW5kIHRoYXQgdGhlIG1ldGhvZCB0aGF0IHVzZXMgKm1vcmUgZmFjdG9ycyogZm9yIGFuIGFzc2V0IGhhdmUgaGlnaGVyIFItc3F1YXJlZCB2YWx1ZXMgYXMgZXhwZWN0ZWQuIEhvd2V2ZXIsIHdoZW4gYm90aCAibGFycyIgYW5kICJzdWJzZXRzIiBjaG9zZSB0aGUgc2FtZSBudW1iZXIgb2YgZmFjdG9ycywgImxhcnMiIGZpdHMgaGF2ZSBhIHNsaWdodGx5IGhpZ2hlciBSLXNxdWFyZWQgdmFsdWVzLgoKCiMjIyAgUzMgZ2VuZXJpYyBtZXRob2RzCk1hbnkgdXNlZnVsIGdlbmVyaWMgYWNjZXNzb3IgZnVuY3Rpb25zIGFyZSBhdmFpbGFibGUgZm9yICJ0c2ZtIiBmaXQgb2JqZWN0czoKCi0gY29lZigpIHJldHVybnMgYSBtYXRyaXggb2YgZXN0aW1hdGVkIG1vZGVsIGNvZWZmaWNpZW50cyBpbmNsdWRpbmcgdGhlIGludGVyY2VwdC4gCi0gZml0dGVkKCkgcmV0dXJucyBhbiB4dHMgZGF0YSBvYmplY3Qgb2YgdGhlIGNvbXBvbmVudCBvZiBhc3NldCByZXR1cm5zIGV4cGxhaW5lZCBieSB0aGUgZmFjdG9yIG1vZGVsLiAKLSByZXNpZHVhbHMoKSByZXR1cm5zIGFuIHh0cyBkYXRhIG9iamVjdCB3aXRoIHRoZSBjb21wb25lbnQgb2YgYXNzZXQgcmV0dXJucyBub3QgZXhwbGFpbmVkIGJ5IHRoZSBmYWN0b3IgbW9kZWwuIAotIHByZWRpY3QoKSB1c2VzIHRoZSBmaXR0ZWQgZmFjdG9yIG1vZGVsIHRvIGVzdGltYXRlIGFzc2V0IHJldHVybnMgZ2l2ZW4gYSBzZXQgb2YgbmV3IG9yIHNpbXVsYXRlZCBmYWN0b3IgcmV0dXJuIGRhdGEuCi0gc3VtbWFyeSgpIHByaW50cyBzdGFuZGFyZCBlcnJvcnMgYW5kIHQtc3RhdGlzdGljcyBmb3IgYWxsIGVzdGltYXRlZCBjb2VmZmljaWVudHMgaW4gYWRkaXRpb24gdG8gUi1zcXVhcmVkIHZhbHVlcyBhbmQgcmVzaWR1YWwgdm9sYXRpbGl0aWVzLiAKCkFyZ3VtZW50IHNlLnR5cGUsIG9uZSBvZiAiRGVmYXVsdCIsICJIQyIgb3IgIkhBQyIsIGFsbG93cyBmb3IgaGV0ZXJvc2tlZGFzdGljaXR5IGFuZCBhdXRvLWNvcnJlbGF0aW9uIGNvbnNpc3RlbnQgZXN0aW1hdGVzIGFuZCBzdGFuZGFyZCBlcnJvcnMgd2hlbmV2ZXIgcG9zc2libGUuIEEgInN1bW1hcnkudHNmbSIgb2JqZWN0IGlzIHJldHVybmVkIHdoaWNoIGNvbnRhaW5zIGEgbGlzdCBvZiBzdW1tYXJ5IG9iamVjdHMgcmV0dXJuZWQgYnkgImxtIiwgImxtLlJvYiIgb3IgImxhcnMiIGZvciBlYWNoIGFzc2V0IGZpdC4KCmBgYHtyfQoKbWV0aG9kcyhjbGFzcz0idHNmbSIpCgpgYGAKCkFsbCBlc3RpbWF0ZWQgY29lZmZpY2llbnRzIGZyb20gdGhlIExTIGZpdCB1c2luZyBhbGwgMyBmYWN0b3JzCmBgYHtyfQoKY29lZihmaXQub2xzKQoKYGBgCgpDb21wYXJlIHJldHVybnMgZGF0YSB3aXRoIGZpdHRlZCBhbmQgcmVzaWR1YWwgdmFsdWVzIGZvciBIQU0xIGZyb20gZml0LmxhcnMKCmBgYHtyfQoKSEFNMS50cyA8LSBtZXJnZShmaXQubGFycyRkYXRhWywxXSwgCiAgICAgICAgICAgICAgICAgZml0dGVkKGZpdC5sYXJzKVssMV0sIAogICAgICAgICAgICAgICAgIHJlc2lkdWFscyhmaXQubGFycylbLDFdKSAKCmNvbG5hbWVzKEhBTTEudHMpIDwtIGMoIkhBTTEucmV0dXJuIiwiSEFNMS5maXR0ZWQiLCJIQU0xLnJlc2lkdWFsIikgCgp0YWlsKEhBTTEudHMpCgojIEludGVycHJldGF0aW9uOgojIGZpdHRlZCAtLT4gdGhlIHJldHVybnMgd2hpY2ggY2FuIGJlIGV4cGxhaW5lZCB0aHJvdWdoIHRoZSBtb2RlbAojIHJlc2lkdWFsIC0tPiB0aGUgcmV0dXJucyB3aGljaCBjYW5ub3QgYmUgZXhwbGFpbmVkIHRocm91Z2ggdGhlIG1vZGVsCmBgYAoKIyMjIFN1bW1hcnkgZm9yIGZpdC5zdWIgY29tcHV0aW5nIEhBQyBzdGFuZGFyZCBlcnJvcwoKYGBge3J9CgpzdW1tYXJ5KGZpdC5zdWIsIHNlLnR5cGU9IkhBQyIpCgpgYGAKCgojIyMgRmFjdG9yIE1vZGVsIENvdmFyaWFuY2UgJiBSaXNrIERlY29tcG9zaXRpb24KCiMjIyMgRmFjdG9yIG1vZGVsIGNvdmFyaWFuY2UKCmBgYHtyfQojIHRoZSBmYWN0b3IgbW9kZWwgY292YXJpYW5jZSBmcm9tIGEgZml0dGVkIGZhY3RvciBtb2RlbC4KZm1Db3YoZml0LnN1YikKCiMgZmFjdG9yIG1vZGVsIHJldHVybiBjb3JyZWxhdGlvbiBwbG90CnBsb3QoZml0LnN1Yiwgd2hpY2g9OCkKYGBgCiMjIyMgU3RhbmRhcmQgZGV2aWF0aW9uIGRlY29tcG9zaXRpb24KCmBgYHtyfQojIGZtU2REZWNvbXAgcGVyZm9ybXMgYSBkZWNvbXBvc2l0aW9uIGZvciBhbGwgYXNzZXRzIGluIHRoZSBnaXZlbiBmYWN0b3IgbW9kZWwgZml0IG9iamVjdApkZWNvbXAgPC0gZm1TZERlY29tcChmaXQuc3ViKQpuYW1lcyhkZWNvbXApCgojIEFsbCBJbmZvcm1hdGlvbiB0b2dldGhlcgpkZWNvbXAKCiMgZ2V0OgpkZWNvbXAkU2QuZm0KIyAgICAgdGhlIGZhY3RvciBtb2RlbCBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGFsbCBhc3NldHMKZGVjb21wJGNTZAojICAgICB0aGUgY29tcG9uZW50IGNvbnRyaWJ1dGlvbnMgdG8gU2QKZGVjb21wJG1TZAojICAgICB0aGUgbWFyZ2luYWwgZmFjdG9yIGNvbnRyaWJ1dGlvbnMgdG8gU2QKZGVjb21wJHBjU2QKIyAgICAgdGhlIHBlcmNlbnRhZ2UgY29tcG9uZW50IGNvbnRyaWJ1dGlvbnMgdG8gU2QKCiMgcGxvdCB0aGUgcGVyY2VudGFnZSBjb21wb25lbnQgY29udHJpYnV0aW9ucyB0byBTZApwbG90KGZpdC5zdWIsIHdoaWNoPTksIGYuc3ViPTE6MykKCmBgYAoKCiMjIyMgVmFsdWUtYXQtUmlzayBkZWNvbXBvc2l0aW9uCgpWYVIgPSBUaGUgdmFsdWUgYXQgcmlzayBmb3IgYSBnaXZlbiBwcm9iYWJpbGl0eSBsZXZlbCBpbmRpY2F0ZXMgdGhlIGFtb3VudCBvZiBsb3NzIHRoYXQgd2lsbCBub3QgYmUgZXhjZWVkZWQgd2l0aGluIGEgZ2l2ZW4gcGVyaW9kIG9mIHRpbWUgd2l0aCB0aGlzIHByb2JhYmlsaXR5CgpgYGB7cn0KCmRlY29tcDEgPC0gZm1WYVJEZWNvbXAoZml0LnN1YikKbmFtZXMoZGVjb21wMSkKCiMgQWxsIEluZm9ybWF0aW9uIHRvZ2V0aGVyCmRlY29tcDEKCiMgZ2V0IHRoZSBmYWN0b3IgbW9kZWwgdmFsdWUtYXQtcmlzayBmb3IgYWxsIGFzc2V0cwpkZWNvbXAxJFZhUi5mbQoKIyBnZXQgdGhlIHBlcmNlbnRhZ2UgY29tcG9uZW50IGNvbnRyaWJ1dGlvbnMgdG8gVmFSCmRlY29tcDEkcGNWYVIKCiMgcGxvdCB0aGUgcGVyY2VudGFnZSBjb21wb25lbnQgY29udHJpYnV0aW9ucyB0byBWYVIKcGxvdChmaXQuc3ViLCB3aGljaD0xMSwgZi5zdWI9MTozKQpgYGAKCiMjIyMgRXhwZWN0ZWQgU2hvcnRmYWxsIGRlY29tcG9zaXRpb24KClRoZSB0ZXJtIHJpc2sgbWVhc3VyZSBpcyBhIGNvbGxlY3RpdmUgdGVybSBmb3Igc3RhdGlzdGljYWwgbWVhc3VyZXMgdGhhdCBjYW4gYmUgdXNlZCB0byBxdWFudGl0YXRpdmVseSBkZXNjcmliZSB0aGUgdW5jZXJ0YWludHkgb2YgYW4gZXZlbnQuClZhUiBpcyBkZWZpbmVkIGFzIHRoZSBhbW91bnQgb2YgbG9zcyB0aGF0IHdpbGwgbm90IGJlIGV4Y2VlZGVkIGluIGEgZ2l2ZW4gcGVyaW9kIG9mIHRpbWUgd2l0aCBhIHNwZWNpZmllZCBwcm9iYWJpbGl0eSBwICgiY29uZmlkZW5jZSBsZXZlbCIgzrEgPSAxIC0gcCkuCgpgYGB7cn0KCmRlY29tcDIgPC0gZm1Fc0RlY29tcChmaXQuc3ViLCBtZXRob2Q9Imhpc3RvcmljYWwiKQpuYW1lcyhkZWNvbXAyKQoKIyBnZXQgdGhlIGZhY3RvciBtb2RlbCBleHBlY3RlZCBzaG9ydGZhbGwgZm9yIGFsbCBhc3NldHMKZGVjb21wMiRFUy5mbQoKIyBnZXQgdGhlIGNvbXBvbmVudCBjb250cmlidXRpb25zIHRvIFNkCmRlY29tcDIkY0VTCgojIGdldCB0aGUgbWFyZ2luYWwgZmFjdG9yIGNvbnRyaWJ1dGlvbnMgdG8gRVMKZGVjb21wMiRtRVMKCiMgZ2V0IHRoZSBwZXJjZW50YWdlIGNvbXBvbmVudCBjb250cmlidXRpb25zIHRvIEVTCmRlY29tcDIkcGNFUwoKIyBwbG90IHRoZSBwZXJjZW50YWdlIGNvbXBvbmVudCBjb250cmlidXRpb25zIHRvIEVTCnBsb3QoZml0LnN1Yiwgd2hpY2g9MTAsIGYuc3ViPTE6MykKYGBgCgojIyMjIFBsb3QKCgojIyMjIEdyb3VwIFBsb3RzCgpgYGB7cn0KCnBsb3QoZml0LnN1Yiwgd2hpY2g9NikKIyBNYWtlIGEgcGxvdCBzZWxlY3Rpb24gKDEtMTIgb3IgMCB0byBleGl0KQoKYGBgCgojIyMjIEluZGl2aWR1YWwgUGxvdHMKCmBgYHtyfQoKcGxvdChmaXQuc3ViLCBwbG90LnNpbmdsZT1UUlVFLCBhc3NldC5uYW1lPSJIQU0xIiwgd2hpY2g9MTApCgpgYGAKYGBge3J9CgpwbG90KGZpdC5zdWIsIHBsb3Quc2luZ2xlPVRSVUUsIGFzc2V0Lm5hbWU9IkhBTTEiLCB3aGljaD0xNCkKZ3JpZCgpCgpgYGAKYGBge3J9CgpwbG90KGZpdC5zdWIsIHBsb3Quc2luZ2xlPVRSVUUsIGFzc2V0Lm5hbWU9IkhBTTEiLCB3aGljaD0xMSkKCmBgYApgYGB7cn0KCnBsb3QoZml0LnN1YiwgcGxvdC5zaW5nbGU9VFJVRSwgYXNzZXQubmFtZT0iSEFNMSIsIHdoaWNoPTEyKQoKYGBgCgojIyBFeGVyY2lzZSA1OiBGdW5kYW1lbnRhbCBGYWN0b3IgTW9kZWxzCgpGb2xsb3cgdGhlIGZpbGUgW2ZmbVZpZ25ldHRlLnBkZl0oaHR0cHM6Ly9naXRodWIuY29tL2JyYXZlcm9jay9GYWN0b3JBbmFseXRpY3MvYmxvYi9tYXN0ZXIvdmlnbmV0dGVzL2ZmbVZpZ25ldHRlLnBkZikgYW5kIGludGVycHJldCB5b3VyIHJlc3VsdHMuCgojIyMgVGhlb3JpZQpUaGUgZ2VuZXJhbCBtYXRoZW1hdGljYWwgZm9ybSBvZiBlcXVpdHkgZnVuZGFtZW50YWwgZmFjdG9yIG1vZGVsIChGRk0pIGltcGxlbWVudGVkIGluIGZhY3RvckFuYWx5dGljcyBpcwpydCA9IM6xdMK3IDEgKyBCdOKIkjFmdCArIM61dCwgdCA9IDEsIDIsIMK3IMK3IMK3ICwgVCAoMSkKCndoZXJlOgotIGVxdWl0eSByZXR1cm5zIHZlY3RvciBydCBhbmQgdGhlIHZlY3RvcnMgMSBhbmQgCi0gzrV0IGFyZSBOIMOXMSB2ZWN0b3JzLCAKLSBCdOKIkjEgaXMgYW4gTiDDl0sgZXhwb3N1cmVzIChyaXNrIGZhY3RvcnMpIG1hdHJpeCwgYW5kIAotIGZ0IGlzIGEgSyDDlyAxIHZlY3RvciBvZiByYW5kb20gZmFjdG9yIHJldHVybnMuIAotIEl0IGlzIGFzc3VtZWQgdGhhdCB0aGUgzrV0IGhhdiB6ZXJvIG1lYW4gd2l0aCBkaWFnb25hbCBjb3ZhcmlhbmNlIG1hdHJpeCBEdCA9IGRpYWcoz4MydCwxLCDPgzJ0LDIsIMK3IMK3IMK3ICwgz4MydCxOKSwgYW5kIGFyZSB1bmNvcnJlbGF0ZWQKd2l0aCB0aGUgZnQKCgpgYGB7cn0KCiMgZmFjdG9yQW5hbHl0aWNzCiMgVGhlIGZvbGxvd2luZyBVLlMuIHN0b2NrIHJldHVybnMgYW5kIGRhdGEgc2V0cyBhcmUgaW5jbHVkZWQgaW4gZmFjdG9yQW5hbHl0aWNzIGZvciBub3c6CiMKIyAxKSBmYWN0b3JEYXRhU2V0RGppYTogCiMgICAgICAgICAgICAgICAgICAgICAgIC0gTW9udGhseSByZXR1cm5zIG9mIDMwIHN0b2NrcyBpbiB0aGUgREpJQSBmcm9tIEphbnVhcnkgMjAwMCB0byBNYXJjaCAyMDEzID0gRG93IEpvbmVzIEluZHVzdHJpYWwgQXZlcmFnZSAKIyAgICAgICAgICAgICAgICAgICAgICAgLSB3aXRoIDUgY29ycmVzcG9uZGluZyBzdHlsZSBmYWN0b3JzOgojICAgICAgICAgICAgICAgICAgICAgICAgICAgLSBNS1RDQVAgIChNYXJrZXQgQ2FwaXRhbGl6YXRpb24pCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAtIEVOVFZBTCAgKEVudGl0bGVkIFZhbHVlKQojICAgICAgICAgICAgICAgICAgICAgICAgICAgLSBQMkIgICAgICgpIFBsYXRmb3JtIHRvIEJ1c2luZXNzCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAtIEVWMlMgICAgKCkKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIC0gU0laRSAgICAoKQojICAgICAgICAgICAgICAgICAgICAgICAtIGFuZCBhIHNlY3RvciBmYWN0b3Igd2l0aCA5IHNlY3RvcnM6CiMgICAgICAgICAgICAgICAgICAgICAgICAgICAtIEVORVJHWSAgKEVuZXJneSksIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgLSBDT1NUQVAgIChDb25zdW1lciBTdGFwbGVzKSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAtIElORFVTVCAgKEluZHVzdHJ5KSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAtIE1BVFJMUyAgKE1hdGVyaWFscyksIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgLSBGSU5TICAgIChGaW5hbmNpYWxzKSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAtIElORk9USyAgKEluZm9ybWF0aW9uIFRlY2hub2xvZ3kpLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIC0gSEVBTFRIICAoSGVhbHRoY2FyZSkKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIC0gQ09ESVNDICAoQ29uc3VtZXIgRGlzY3JldGlvbmFyeSksIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgLSBURUxDT00gIChUZWxlY29tbXVuaWNhdGlvbnMpXSAKIyAKIwojIDIpIGZhY3RvckRhdGFTZXREamlhNVlyczogCiMgICAgICAgICAgICAgICAgICAgICAgIC0gQSBmaXZlLXllYXIgc2VnbWVudCBvZiBmYWN0b3JEYXRhU2V0RGppYSBmcm9tIEphbnVhcnkgMjAwOCB0byBEZWNlbWJlciAyMDEyLgojCiMKIyAzKSB3dHNEamlhR212TG86IAojICAgICAgICAgICAgICAgICAgICAgICAtIFdlaWdodCB2ZWN0b3Igb2YgZGltZW5zaW9uIDMwIGNvbnRhaW5pbmcgdGhlIHdlaWdodHMgb2YgYSBsb25nLW9ubHkgCiMgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsIG1pbmltdW0gdmFyaWFuY2UgKEdNVikgcG9ydGZvbGlvIGZvciB0aGUgMzAgc3RvY2tzIGluIHRoZSBmYWN0b3JEYXRhU2V0RGppYTVZcnMgZGF0YSBzZXQuCiMgICAgICAgICAgICAgICAgICAgICAgIC0gVGhlIHdlaWdodCB2ZWN0b3Igd2FzIG9idGFpbmVkIHVzaW5nIFBvcnRmb2xpb0FuYWx0eWljcyB3aXRoIHRoZSB1c3VhbCBzYW1wbGUgY292YXJpYW5jZSBtYXRyaXggCiMgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZWQgb24gdGhlIDUgeWVhcnMgb2YgcmV0dXJucyBpbiBmYWN0b3JEYXRhU2V0RGppYTVZcnMuCgoKZGF0YSgiZmFjdG9yRGF0YVNldERqaWE1WXJzIikgCgpkYXRhRGppYTVZciA9IGZhY3RvckRhdGFTZXREamlhNVlycyAKCmhlYWQoZGF0YURqaWE1WXIsNSkgCmBgYCAKIAogCiMjIyAxLiBGaXR0aW5nIGEgRnVuZGFtZW50YWwgRmFjdG9yIE1vZGVsIC0gRkZNIApBIEZGTSBpcyBnZW5lcmFsbHkgZml0IGJ5IGEgdHdvLXN0ZXAgbWV0aG9kOgoxKSB1c2luZyBsZWFzdCBzcXVhcmVzIG9yIHJvYnVzdCByZWdyZXNzaW9uIG1ldGhvZHMgaW4gdGhlIGZpcnN0IHN0ZXAsIAoyKSBhbmQgdXNpbmcgd2VpZ2h0ZWQgbGVhc3Qgc3F1YXJlcyBvciB3ZWlnaHRlZCByb2J1c3QgcmVncmVzc2lvbiBpbiB0aGUgc2Vjb25kIHN0ZXAgd2hlcmUgdGhlIHdlaWdodHMgYXJlIGNvbXB1dGVkIGluIHRoZSBmaXJzdCBzdGVwLgoKYGBge3J9IAojIFRoZSBGdW5kYW1lbnRhbC1GYWN0b3ItTW9kZWwtRnVuY3Rpb246IGZpdEZmbQoKZml0RGppYTVZciA9IGZpdEZmbShkYXRhRGppYTVZciwgYWRkSW50ZXJjZXB0ID0gVCwgCiAgICAgICAgICAgICAgICAgICAgYXNzZXQudmFyID0gIlRJQ0tFUiIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBhc3NldC52YXIgPSBuYW1lIG9mIHZhcmlhYmxlIGZvciBhc3NldCBuYW1lcyAKICAgICAgICAgICAgICAgICAgICByZXQudmFyID0gIlJFVFVSTiIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJldC52YXIgPSBuYW1lIG9mIHZhcmlhYmxlIGZvciBhc3NldCByZXR1cm5zIAogICAgICAgICAgICAgICAgICAgIGRhdGUudmFyID0gIkRBVEUiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZGF0ZS52YXIgPSBuYW1lIG9mIHZhcmlhYmxlIGNvbnRhaW5pbmcgdGhlIGRhdGVzIAogICAgICAgICAgICAgICAgICAgIGV4cG9zdXJlLnZhcnMgPSBjKCJTRUNUT1IiLCJTSVpFIiwgIlAyQiIsICJFVjJTIiksICAgICMgZXhwb3NydWUudmFyID0gdmFyaWFibGVzIGNvbnRhaW5pbmcgdGhlIGZ1bmRhbWVudGFsIGZhY3RvciBleHBvc3VyZXMgCiAgICAgICAgICAgICAgICAgICAgei5zY29yZSA9ICJjcm9zc1NlY3Rpb24iKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB6LnNjb3JlIGhhcyB0byBiZSBvbmUgb2YgIm5vbmUiLCAiY3Jvc3NTZWN0aW9uIiwgb3IgInRpbWVTZXJpZXMiIAoKbmFtZXMoZml0RGppYTVZcikgCmBgYCAKIyMjIyAxLjEuIE1vZGVsIEZpdCBSLVNxdWFyZWQgVmFsdWVzCk9uZSBvZiB0aGUgbW9zdCBiYXNpYyBtb2RlbCBmaXQgc3RhdGlzdGljcyBpcyB0aGUgUi1zcXVhcmVkLCBhbmQgeW91IGNhbiBhc3Nlc3MgdGhlIGdvb2RuZXNzIG9mIHlvdXIgRkZNIGZpdHMgYnkgdXNpbmcgdGhlIGZ1bmN0aW9uIGZmbVJzcSB0byBtYWtlIGEgcGxvdCBvZiB0aGUgdGltZSBzZXJpZXMgb2YgUi1zcXVhcmVkIHZhbHVlcyBmb3IgZWFjaCBvZiB0aGUgNjAgZml0cyBvdmVyIHRoZSBmaXZlLXllYXIgd2luZG93LiBUaGlzIGZ1bmN0aW9uIGNvbXB1dGVzIGFuZCBwbG90cyB0aGUgdGltZSBzZXJpZXMgb2Ygb3JkaW5hcnkgUi1zcXVhcmVkIGJ5IGRlZmF1bHQsIGJ1dCBpdCBjYW4gZG8gdGhhdCBmb3IgdGhlIGFkanVzdGVkIFItc3F1YXJlZCwgb3IgYm90aC4KCmBgYHtyfSAKCiMgRml0IFItU3F1YXJlZCBWYWx1ZXMKCmZtUnNxKGZpdERqaWE1WXIsCiAgICAgIHJzcSA9IFQsICAgICAgICAgICAgICAjIGxvZ2ljYWw7IGlmIFRSVUUsIEZhY3RvciBNb2RlbCBSLXNxdWFyZWQgdmFsdWVzIGFyZSBjb21wdXRlZCBmb3IgdGhlIHBvcnRmb2xpby4gRGVmYXVsdCBpcyBUUlVFLgogICAgICByc3FBZGogPSBULCAgICAgICAgICAgIyBsb2dpY2FsOyBpZiBUUlVFLCBBZGp1c3RlZCBSLXNxdWFyZWQgdmFsdWVzIGFyZSBjb21wdXRlZCBmb3IgdGhlIHBvcnRmb2xpby4gRGVmYXVsdCBpcyBGQUxTRS4KICAgICAgcGx0LnR5cGUgPSAyLCAgICAgICAgICMgMSBpbmRpY2F0ZXMgYmFycGxvdCwgMiBpbmRpY2F0ZXMgdGltZSBzZXJpZXMgeHkgcGxvdC4gRGVmYXVsdCBpcyAyLgogICAgICBpc1ByaW50ID0gRiwgCiAgICAgIGx3ZCA9IDAuNywgCiAgICAgIHN0cmlwVGV4dC5jZXggPSAwLjgsIAogICAgICBheGlzLmNleCA9IDAuOCkgCiAKIyBJbnRlcnByZXRhdGlvbjoKIyAxKSBVcHBlciBQbG90OiBNZWFuIFItU3F1YXJlZCBhY3Jvc3MgcGVyaW9kcyA9IDAuNzggKE91dHB1dCBvZiB0aGUgSnVuaykgCiMgICAgLT4gcHJvYmxlbSwgUi1TcXVhcmVkIGluY3JlYXNlcyBldmVyeXRpbWUgYW4gaW5kZXBlbmRhbnQgdmFyaWFibGUgaXMgYWRkZWQsIHdoaWNoIG1lYW5zIHRoZSBtb3JlIGluZGVwZW5kYW50IHZhcmlhYmxlcyB0aGUgaGlnaGVyIHRoZSBSLVNxdWFyZWQuIAojIDIpIE1lYW4gYWRqdXN0ZWQgUi1TcXVhcmVkID0gMC41NCAoT3V0cHV0IG9mIHRoZSBKdW5rKSAKIyAgICAtPiBhcyBzb29uIGFzIHdlIHRha2UgdGhlIHByb2JsZW0gd2l0aCBSLVNxdWFyZWQgaW50byBhY2NvdW50IGFuZCB1c2UgdGhlIGFkanVzdGVkIG1lYW4sIHdlIHNlZSB0aGF0IHRoZSB2YWx1ZSBkcm9wcyBmcm9tIDc4JSB0byA1NCUgYW5kIHRoYXQgdGhlcmUgCiMgICAgICAgYXJlIGV2ZW4gbmVnYXRpdmUgc2luZ2xlIHZhbHVlcy4gCiAKYGBgIAojIyMjIDEuMiBNb2RlbCBGaXQgVmFyaWFuY2UgSW5mbGF0aW9uIEZhY3RvcnMgLSAoVklG4oCZcykgCldoZW4geW91ciBtb2RlbCBpbmNsdWRlcyBjb250aW51b3VzIHN0eWxlIGZhY3RvciB2YXJpYWJsZXMgdGhlIGZ1bmN0aW9uIGZmbVJzcSBhbHNvIGFsbG93cyB5b3UgdG8gY29tcHV0ZSBhbmQgZGlzcGxheSB0aGUgdGltZSBzZXJpZXMgb2YgdmFyaWFuY2UgaW5mbGF0aW9uIGZhY3RvcnMgKFZJRuKAmXMpLiBUaGVzZSBjYW4gaGVscCB5b3UgZGV0ZXJtaW5lIHdoZXRoZXIgb3Igbm90IHRoZXJlIGFyZSBhbnkgcmVncmVzc2lvbiBjb2xsaW5lYXJpdHkgcHJvYmxlbXMuCiAKYGBge3J9IAoKIyB0aGUgdGltZSBzZXJpZXMgb2YgbWVhbiB2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9ycyAoVklG4oCZcykgCnZpZihmaXREamlhNVlyLCAKICAgIGlzUGxvdCA9IFQsIAogICAgaXNQcmludCA9IEYsIAogICAgbHdkID0gMC43LCAKICAgIHN0cmlwVGV4dC5jZXggPSAwLjgsIAogICAgYXhpcy5jZXggPSAwLjgpIAogCiNNdWx0aWtvbGxpbmVhcml0w6R0IGlzdCBlaW4gUHJvYmxlbSBkZXIgUmVncmVzc2lvbnNhbmFseXNlIHVuZCBsaWVndCB2b3IsIHdlbm4gendlaSBvZGVyIG1laHIgZXJrbMOkcmVuZGUgVmFyaWFibGVuIGVpbmUgc2VociBzdGFya2UgS29ycmVsYXRpb24gbWl0ZWluYW5kZXIgaGFiZW4uIFp1bSBlaW5lbiB3aXJkIG1pdCB6dW5laG1lbmRlciBNdWx0aWtvbGxpbmVhcml0w6R0IGRhcyBWZXJmYWhyZW4genVyIFNjaMOkdHp1bmcgZGVyIFJlZ3Jlc3Npb25za29lZmZpemllbnRlbiBpbnN0YWJpbCB1bmQgQXVzc2FnZW4genVyIFNjaMOkdHp1bmcgZGVyIFJlZ3Jlc3Npb25za29lZmZpemllbnRlbiB6dW5laG1lbmQgdW5nZW5hdS4gWnVtIGFuZGVyZW4gaXN0IGRpZSBNb2RlbGxpbnRlcnByZXRhdGlvbiBuaWNodCBtZWhyIGVpbmRldXRpZy4gRGFzIGtsYXNzaXNjaGUgU3ltcHRvbSB2b24gc3RhcmtlciBNdWx0aWtvbGxpbmVhcml0w6R0IGlzdCBlaW4gaG9oZXMgQmVzdGltbXRoZWl0c21hw58gZWluaGVyZ2VoZW5kIG1pdCBuaWVkcmlnZW4gdC1XZXJ0ZW4gZsO8ciBkaWUgZWluemVsbmVuIFJlZ3Jlc3Npb25zcGFyYW1ldGVyLgoKYGBgIAojIyMjIDEuMyBNb2RlbCBGaXQgdC1TdGF0aXN0aWNzClBsb3RzIG9mIHRoZSB0aW1lIHNlcmllcyBvZiB0LXN0YXRpc3RpY3MgZm9yIHRoZSBmYWN0b3JzIGluIGFuIEZGTSBmaXR0ZWQgbW9kZWwsIHdpdGggaG9yaXpvbnRhbCBkYXNoZWQgbGluZXMgcHJvdmlkZWQgdG8ganVkZ2Ugd2hldGhlciBvciBub3QgYSBmYWN0b3IgaXMgc2lnbmlmaWNhbnQgYXQgdGhlIDUlIGxldmVsLCBtYXkgYmUgb2J0YWluZWQgd2l0aCB0aGUgZnVuY3Rpb24gZmZtVHN0YXRzLgogCmBgYHtyfSAKCiMgVGhlIHRpbWUgc2VyaWVzIG9mIHQtc3RhdGlzdGljcyBmb3IgdGhlIGZhY3RvcnMgKDUlIHNpZ25pZmljYW50IGxldmVsKQpmbVRzdGF0cyhmaXREamlhNVlyLCAKICAgICAgICAgd2hpY2hQbG90ID0gInRTdGF0cyIsIAogICAgICAgICBjb2xvciA9ICJibHVlIiwgCiAgICAgICAgIGx3ZCA9IDAuNywgCiAgICAgICAgIGxheW91dCA9IGMoMywgNCksIAogICAgICAgICBzdHJpcFRleHQuY2V4ID0gMC44LCAKICAgICAgICAgYXhpcy5jZXggPSAwLjgpIAoKIyBJbnRlcnByZXRhdGlvbjoKCgpgYGAgCiAKYGBge3J9IAojIGZtVHN0YXRzIGNhbiBhbHNvIGNvbXB1dGUgdGhlIG51bWJlciBvZiBzaWduaWZpY2FudCB0LXN0YXRpc3RpY3M6CiMgICAgICAgICB0aGUgbnVtYmVyIG9mIHBvc2l0aXZlLCAKIyAgICAgICAgIG5lZ2F0aXZlIGFuZCAKIyAgICAgICAgIHRvdGFsIHNpZ25pZmljYW50IHQtc3RhdGlzdGljcyAKCmZtVHN0YXRzKGZpdERqaWE1WXIsIAogICAgICAgICB3aGljaFBsb3QgPSAic2lnbmlmaWNhbnRUc3RhdHNWIiwgCiAgICAgICAgIGNvbG9yID0gImJsdWUiLCAKICAgICAgICAgc3RyaXBUZXh0LmNleCA9IDAuOCwgCiAgICAgICAgIGF4aXMuY2V4ID0gMC44LCAKICAgICAgICAgbGF5b3V0ID0gYygzLCA0KSkgCgojIEludGVycHJldGF0aW9uOiAzIHN0eWxlIGZhY3RvcnMgKyBtYXJrZXQgICsgOCBzZWN0b3JzCgojIHJlZCBsaW5lcyBzaG93cyBjcml0aWNhbCB2YWx1ZXMgdCBzdGF0aXN0aWM7IGV2ZXJ5dGhpbmcgbGFyZ2VyIGluIChhYm9sdXRlIHZhbHVlKSAgdGhlbiBjcml0aWNhbCB2YWx1ZSBpcyBzaWdubmlmaWNhbnQgCgojIHJlc3VsdCBvZiBjb2xpbmVhcml0eSAtPiBub3QgbWFueSBzaWduaWZpY2FudCBwYXJhbWV0ZXJzCgojIHNlZSBiZWxvdzogcmVsYXRpdmxleSBsb3cgYW1vdW50IG9mIHNpZ25pZmljYW50IHBhcmFtZXRlcnMgKGV4ZWNlcHQgZm9yIG1hcmtldCkKYGBgIAogCgojIyMgMi4gUmlzayBhbmQgUGVyZm9ybWFuY2UgUmVwb3J0IAogVGhlIGZhY3RvckFuYWx5dGljcyBwYWNrYWdlIGNvbnRhaW5zIHRoZSBmb2xsb3dpbmcgcmlzayBhbmQgcGVyZm9ybWFuY2UgcmVwb3J0aW5nIGZ1bmN0aW9uczoKIDEpIHJlcEV4cG9zdXJlcwogMikgcmVwUmV0dXJuCiAzKSByZXBSaXNrIAogCldlIGlsbHVzdHJhdGUgdGhlIHVzZSBvZiBlYWNoIG9mIHRoZXNlIGluIHR1cm4gdXNpbmcgImZpdERqaWE1WXIiIGFuZCB0aGUgY29ycmVzcG9uZGluZyBnbG9iYWwgbWluaW11bSB2YXJpYW5jZSBsb25nLW9ubHkgcG9ydGZvbGlvIHdlaWdodHMgb2JqZWN0ICJ3dHNEamlhR212TG8iIAogCmBgYHtyfSAKCiMgbG9hZCB0aGUgbG9uZy1vbmx5IGdsb2JhbCBtaW5pbXVtIHZhcmlhbmNlIHBvcnRmb2xpbyB3ZWlnaHRzIHZlY3RvciAKZGF0YSh3dHNEamlhR212TG8pIAoKIyBhbmQgZ2l2ZSBpdCB0aGUgc2hvcnRlciBuYW1lIHd0c0RqaWEgCnd0c0RqaWEgPSB3dHNEamlhR212TG8gCgpgYGAgCiAKIAojIyMjIDIuMSkgcmVwRXhwb3N1cmUgClRoZSBwb3J0Zm9saW8gZXhwb3N1cmUgdG8gYSBnaXZlbiByaXNrIGZhY3RvciBpcyB0aGUgaW5uZXIgKGRvdCkgcHJvZHVjdCBvZiB0aGUgcG9ydGZvbGlvIHdlaWdodCB2ZWN0b3Igd2l0aCB0aGUgY29sdW1uIG9mIHRoZSBleHBvc3VyZXMgbWF0cml4IEJ04oiSMSBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiBmYWN0b3IuIFRoZSBzdHlsZSBmYWN0b3JzIHZhcnkgb3ZlciB0aW1lLCBidXQgdGhlIHNlY3RvciBmYWN0b3JzIGFyZSBmaXhlZCBhbmQgZWFjaCBzZWN0b3IgaXMgcmVwcmVzZW50ZWQgYnkgYSBjb2x1bW4gb2YgemVyb+KAmXMgYW5kIG9uZXMuIFRodXMgdGhlIHBvcnRmb2xpbyBleHBvc3VyZSB0byBzdHlsZSBmYWN0b3JzIHdpbGwgdmFyeSBvdmVyIHRpbWUgYW5kIHRodXMgaGF2ZSBhIGRpc3RyaWJ1dGlvbiB3aXRoIGEgbWVhbiBhbmQgdm9sYXRpbGl0eS4gT24gdGhlIG90aGVyIGhhbmQgdGhlIHBvcnRmb2xpbyBleHBvc3VyZSB0byBzZWN0b3IgZmFjdG9ycyB3aWxsIGhhdmUgYSBmaXhlZCB2YWx1ZSBkZXBlbmRpbmcgb24gdGhlIHBvcnRmb2xpbyB3ZWlnaHRzIGFuZCBudW1iZXIgb2YgZmlybXMgaW4gYSBnaXZlbiBzZWN0b3IuCiAKYGBge3J9IAoKIyBjb21wdXRlIHZvbGF0aWxpdGllcyBvZiB0aGUgc3R5bGUgZmFjdG9ycyBhbmQgc2VjdG9yIGZhY3RvcnMgCnJlcEV4cG9zdXJlcyhmaXREamlhNVlyLAogICAgICAgICAgICAgd3RzRGppYSwKICAgICAgICAgICAgIGlzUGxvdCA9IEYsCiAgICAgICAgICAgICBkaWdpdHMgPSAxLCAKICAgICAgICAgICAgIHN0cmlwVGV4dC5jZXggPSAwLjgsCiAgICAgICAgICAgICBheGlzLmNleCA9IDAuOCkgCgojIEludGVycHJldGF0aW9uOgojIEV4cG9zdXJlIGdlbmVyYWxseSByZWZlcnMgdG8gdGhlIGZhY3Qgb2YgYmVpbmcgZXhwb3NlZCB0byBhIHJpc2suCiMgSnVzdCB0aHJlZSBmYWN0b3JzIGhhdmUgYSB2b2xhdGlsaXR5OgojIDEpIFN0eWxlIGZhY3RvciBQMkI6IHdpdGggMjAuMC4gCiMgMikgU3R5bGUgZmFjdG9yIEVWMlM6IHdpdGggLTMxLjUKIyAzKSBTdGx5ZSBmYWN0b3IgU2l6ZTogd2l0aCA0LjYKCmBgYCAKIAogCiAKYGBge3J9IAoKIyBwbG90IHRoZSB2b2xhdGlsaXRpZXMgb2YgdGhlIHN0eWxlIGZhY3RvcnMgYW5kIHNlY3RvciBmYWN0b3JzIApyZXBFeHBvc3VyZXMoZml0RGppYTVZciwgCiAgICAgICAgICAgICB3dHNEamlhLCAKICAgICAgICAgICAgIGlzUHJpbnQgPSBGLCAKICAgICAgICAgICAgIGlzUGxvdCA9IFQsIAogICAgICAgICAgICAgd2hpY2ggPSAzLCAKICAgICAgICAgICAgIGFkZC5ncmlkID0gRiwgCiAgICAgICAgICAgICB6ZXJvTGluZSA9IFQsIAogICAgICAgICAgICAgY29sb3IgPSAiQmx1ZSIpIApgYGAgCiAKIApgYGB7cn0gCgojIHBsb3QgdGhlIHRpbWUgc2VyaWVzIG9mIHRoZSBzdHlsZSBmYWN0b3IgZXhwb3N1cmVzIApyZXBFeHBvc3VyZXMoZml0RGppYTVZciwgCiAgICAgICAgICAgICB3dHNEamlhLCAKICAgICAgICAgICAgIGlzUHJpbnQgPSBGLCAKICAgICAgICAgICAgIGlzUGxvdCA9IFQsIAogICAgICAgICAgICAgd2hpY2ggPSAxLCAKICAgICAgICAgICAgIGFkZC5ncmlkID0gRiwgCiAgICAgICAgICAgICB6ZXJvTGluZSA9IFQsIAogICAgICAgICAgICAgY29sb3IgPSAiQmx1ZSIsIAogICAgICAgICAgICAgc3RyaXBUZXh0LmNleCA9IDAuOCwKICAgICAgICAgICAgIGF4aXMuY2V4ID0gMC44KSAKCmBgYCAKIApgYGB7cn0gCgojZGlzcGxheSBib3hwbG90cyBvZiB0aG9zZSBleHBvc3VyZXMgCnJlcEV4cG9zdXJlcyhmaXREamlhNVlyLAogICAgICAgICAgICAgd3RzRGppYSwKICAgICAgICAgICAgIGlzUHJpbnQgPSBGQUxTRSwgCiAgICAgICAgICAgICBpc1Bsb3QgPSBUUlVFLAogICAgICAgICAgICAgd2hpY2ggPSAyLAogICAgICAgICAgICAgbm90Y2ggPSBGLAogICAgICAgICAgICAgbGF5b3V0ID0gYygzLDMpKSAKCmBgYCAKIAogCiMjIyMgMi4yKSByZXBSZXR1cm4gClRoZSBmdW5jdGlvbiByZXBSZXRldXJuIHByb3ZpZGVzIHlvdSB3aXRoIHRoZSBmb2xsb3dpbmcgY2hvaWNlcyBvZiBncmFwaGljYWwgcmVwb3J0cywgdGhlIHJlc3VsdHMgb2Ygd2hpY2ggd2lsbCBhbHNvIGJlIHByaW50ZWQgYmVjYXVzZSBvZiB0aGUgZGVmYXVsdCBwcmludGluZyBvcHRpb24gaXNQcmludCA9IFQ6CjEuIFRpbWUgU2VyaWVzIHBsb3Qgb2YgcG9ydGZvbGlvIHJldHVybnMgZGVjb21wb3NpdGlvbgoyLiBUaW1lIFNlcmllcyBwbG90IG9mIHBvcnRmb2xpbyBzdHlsZSBmYWN0b3JzIHJldHVybnMKMy4gVGltZSBTZXJpZXMgcGxvdCBvZiBwb3J0Zm9saW8gc2VjdG9yIHJldHVybnMKNC4gQm94cGxvdCBvZiBQb3J0Zm9saW8gUmV0dXJucyBDb21wb25lbnRzLgoKIApgYGB7cn0gCiMgY2FsdWNsYXRlIG1lYW4gYW5kIHZvbGF0aWxpdHkgb2YgdGhlIHZhcmlvdXMgcG9ydGZvbGlvIHJldHVybiBjb21wb25lbnRzIHdpdGggdGhlIGhlbHAgb2YgcmVwUmV0dXJuIApyZXBSZXR1cm4oZml0RGppYTVZciwKICAgICAgICAgIHd0c0RqaWEsCiAgICAgICAgICBpc1Bsb3QgPSBGQUxTRSwKICAgICAgICAgIGRpZ2l0cyA9IDIpIAoKIyBJbnRlcnByZXRhdGlvbjogCmBgYCAKIApgYGB7cn0gCgojIFBsb3QgcG9ydGZvbGlvIHJldHVybnMgZGVjb21wb3NpdGlvbiAKcmVwUmV0dXJuKGZpdERqaWE1WXIsCiAgICAgICAgICB3dHNEamlhLAogICAgICAgICAgaXNQcmludCA9IEZBTFNFLAogICAgICAgICAgaXNQbG90ID0gVFJVRSwgCiAgICAgICAgICB3aGljaCA9IDEsCiAgICAgICAgICBhZGQuZ3JpZCA9IFRSVUUsCiAgICAgICAgICBzY2FsZVR5cGUgPSAic2FtZSIsIAogICAgICAgICAgY29sb3IgPSAiQmx1ZSIsCiAgICAgICAgICBzdHJpcFRleHQuY2V4ID0gMC44LAogICAgICAgICAgYXhpcy5jZXggPSAwLjgpIAoKIyBJbnRlcnByZXRhdGlvbjogCgpgYGAgCiAKYGBge3J9IAoKIyBQbG90IHBvcnRmb2xpbyBzdHlsZXMgZmFjdG9yIHJldHVybiAKcmVwUmV0dXJuKGZpdERqaWE1WXIsIAogICAgICAgICAgd3RzRGppYSwgCiAgICAgICAgICBpc1ByaW50ID0gRkFMU0UsCiAgICAgICAgICBpc1Bsb3QgPSBUUlVFLCAKICAgICAgICAgIHdoaWNoID0gMiwKICAgICAgICAgIGFkZC5ncmlkID0gVFJVRSwKICAgICAgICAgIHplcm9MaW5lID0gVCwKICAgICAgICAgIGNvbG9yID0gIkJsdWUiLCAKICAgICAgICAgIHNjYWxlVHlwZSA9ICJzYW1lIiwKICAgICAgICAgIHN0cmlwVGV4dC5jZXggPSAwLjgsCiAgICAgICAgICBheGlzLmNleCA9IDAuOCkgCgojIEludGVycHJldGF0aW9uOiAKCmBgYCAKIApgYGB7cn0gCgojIFBsb3QgcG9ydGZvbGlvIHNlY3RvcnMgcmV0dXJuIApyZXBSZXR1cm4oZml0RGppYTVZciwKICAgICAgICAgIHd0c0RqaWEsCiAgICAgICAgICBpc1ByaW50ID0gRkFMU0UsCiAgICAgICAgICBpc1Bsb3QgPSBUUlVFLCAKICAgICAgICAgIHdoaWNoID0gMywKICAgICAgICAgIGFkZC5ncmlkID0gVFJVRSwKICAgICAgICAgIHplcm9MaW5lID0gVCwKICAgICAgICAgIGNvbG9yID0gIkJsdWUiLCAKICAgICAgICAgIHNjYWxlVHlwZSA9ICJzYW1lIiwKICAgICAgICAgIHN0cmlwVGV4dC5jZXggPSAwLjgsCiAgICAgICAgICBheGlzLmNleCA9IDAuOCkgCgojIEludGVycHJldGF0aW9uOiAKCmBgYCAKIApgYGB7cn0gCgojIEJveHBsb3Qgb2YgUG9ydGZvbGlvIFJldHVybnMgQ29tcG9uZW50cyAKcmVwUmV0dXJuKGZpdERqaWE1WXIsCiAgICAgICAgICB3dHNEamlhLAogICAgICAgICAgaXNQcmludCA9IEZBTFNFLAogICAgICAgICAgaXNQbG90ID0gVFJVRSwKICAgICAgICAgIHdoaWNoID0gNCkgCgojIEludGVycHJldGF0aW9uOiAKCmBgYCAKCiAKIAojIyMjIDIuMykgcmVwUmlzayAKVGhlIGZ1bmN0aW9uICpyZXBSaXNrKiBhbGxvd3Mgb25lIHRvIGNvbXB1dGUgYW5kIGRpc3BsYXkgKGdyYXBoaWNhbGx5IGFuZCBpbiB0YWJ1bGFyIGZvcm0pIGZhY3RvciBkZWNvbXBvc2l0aW9ucyBvZiByaXNrIGZvciBhIHBvcnRmb2xpbyBhbmQgZm9yIGVhY2ggb2YgdGhlIGFzc2V0cyB1c2VkIHRvIGZpdCBhIGZ1bmRhbWVudGFsIGZhY3RvciBtb2RlbCB3aXRoIGZpdEZmbS4gVGhlIHJpc2sgbWVhc3VyZSBjYW4gYmUgY2hvc2VuIGFzOgotIHN0YW5kYXJkIGRldmlhdGlvbi92b2xhdGlsaXR5IChTRCkKLSBleHBlY3RlZCBzaG9ydGZhbGwgKEVTKQotIG9yIHZhbHVlLWF0LXJpc2sgKFZhUikKCmFuZCB0aGUgZmFjdG9yIHJpc2sgZGVjb21wb3NpdGlvbiBjYW4gYmUgY2hvc2VuIGFzOgotIGZhY3RvciBwZXJjZW50IGNvbnRyaWJ1dGlvbiB0byByaXNrIChGUENSKQotIGZhY3RvciBjb250cmlidXRpb24gdG8gcmlzayAoRkNSKSAKLSBvciBmYWN0b3IgbWFyZ2luYWwgY29udHJpYnV0aW9uIHRvIHJpc2sgKEZNQ1IpLiAKIAogCmBgYHtyfSAKIyBzdGFuZGFyZCBkZXZpYXRpb24vdm9sYXRpbGl0eSAoU0QpCiMgZmFjdG9yIHBlcmNlbnQgY29udHJpYnV0aW9uIHRvIHJpc2sgLSAoRlBDUikKCiMgRmlyc3Qgd2UgY29tcHV0ZSBhbiBGUENSIGRlY29tcG9zaXRpb24gb2YgdGhlIHBvcnRmb2xpbyBhbmQgaW5kaXZpZHVhbCBhc3NldHMgdXNpbmcgU2QgYXMgdGhlIHJpc2sgbWVhc3VyZSwgYW5kIHByb3ZpZGUgYm90aCBMYXR0aWNlIHZpc3VhbGl6YXRpb24gYW5kIHRhYnVsYXIgZGlzcGxheXMuIEZvciB0aGUgTGF0dGljZSBkaXNwbGF5IHRoZSBhcmd1bWVudCBzbGljZWJ5ID0g4oCcZmFjdG9y4oCdIHNwZWNpZmllcyB0aGF0IHRoZSBwYW5lbCBjb25kaXRpb25pbmcgaXMgYnkgcmlzayBmYWN0b3IgYW5kIHRoZSBjaG9pY2UgbGF5b3V0ID0gYyg1LDEpIHJlc3VsdHMgaW4gYSBzaW5nbGUgcm93IHdpdGggZml2ZSBwYW5lbHMuIFdlIHVzZWQgbnJvd1ByaW50ID0gMTAgdG8gc2hvcnRlbiB0aGUgcHJpbnRlZCBvdXRwdXQgZnJvbSBvbmUgcm93IGZvciB0aGUgcG9ydGZvbGlvIGZhY3RvciByaXNrIGRlY29tcG9zaXRpb24gYW5kIDIyIHJvd3MgKHdlIGFyZSBvbmx5IHVzaW5nIDIyIG9mIHRoZSBESklBIHN0b2NrcyBhdCB0aGUgbW9tZW50KSBmb3IgdGhlIHN0b2NrIGZhY3RvciByaXNrIGRlY29tcG9zaXRpb25zIHRvIG9uZSByb3cgZm9yIHRoZSBwb3J0Zm9saW8gYW5kIDkgcm93cyBmb3IgdGhlIGFzc2V0cy4gCiAKZml0RGppYTVZckludFN0eWxlID0gZml0RmZtKGRhdGEgPSBkYXRhRGppYTVZciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9zdXJlLnZhcnMgPSBjKCJTSVpFIiwgIlAyQiIsICJFVjJTIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0ZS52YXIgPSAiREFURSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0LnZhciA9ICJSRVRVUk4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2V0LnZhciA9ICJUSUNLRVIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpdC5tZXRob2QgPSAiV0xTIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB6LnNjb3JlID0gImNyb3NzU2VjdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkSW50ZXJjZXB0ID0gVCkgCiAKcmVwUmlzayhmaXREamlhNVlySW50U3R5bGUsIAogICAgICAgIHd0c0RqaWEsIAogICAgICAgIHJpc2sgPSAiU2QiLCAKICAgICAgICBkZWNvbXAgPSAiRlBDUiIsIAogICAgICAgIG5yb3dQcmludCA9IDEwLCAKICAgICAgICBzbGljZWJ5ID0gImZhY3RvciIsIAogICAgICAgIGlzUHJpbnQgPSBULCAKICAgICAgICBpc1Bsb3QgPSBULCAKICAgICAgICBsYXlvdXQgPSBjKDUsIDEpLCAKICAgICAgICBzdHJpcFRleHQuY2V4ID0gMC44LCAKICAgICAgICBheGlzLmNleCA9IDAuOCkgCgojIEludGVycHJldGF0aW9uOiAKCgpgYGAgCiAKYGBge3J9IAojIGV4cGVjdGVkIHNob3J0ZmFsbCAoRVMpCiMgZmFjdG9yIHBlcmNlbnQgY29udHJpYnV0aW9uIHRvIHJpc2sgLSAoRlBDUikKCiMgTm93IHdlIHVzZSBleHBlY3RlZCBzaG9ydGZhbGwgKEVTKSB0byBkbyBhbiBGUENSIGRlY29tcG9zaXRpb24gYW5kIHByb3ZpZGUgb25seSB0aGUgTGF0dGljZSAKcmVwUmlzayhmaXREamlhNVlySW50U3R5bGUsIAogICAgICAgIHd0c0RqaWEsIAogICAgICAgIHJpc2sgPSAiRVMiLCAKICAgICAgICBkZWNvbXAgPSAiRlBDUiIsIAogICAgICAgIG5yb3dQcmludCA9IDEwLCAKICAgICAgICBzbGljZWJ5ID0gImZhY3RvciIsIAogICAgICAgIGlzUHJpbnQgPSBGLCAKICAgICAgICBpc1Bsb3QgPSBULCAKICAgICAgICBsYXlvdXQgPSBjKDUsIDEpLAogICAgICAgIHN0cmlwVGV4dC5jZXggPSAwLjgsIAogICAgICAgIGF4aXMuY2V4ID0gMC44KSAKCiMgSW50ZXJwcmV0YXRpb246IAojIEhvdyBtYW55IHBlcmNlbnQgb2Ygc3RhbmRhcmQgZGV2aWF0aW9uIGFyZSBkZXRlcm1pbmRlZCBieSBzeXN0ZW1pYyByaXNrIChzaXplLCBwMmIsIGV2MnMpIGFuZCBpZGlvc3luY3JhdGljIHJpc2sgKFJlc2lkKQpgYGAgCiAKYGBge3J9IAoKIyBleHBlY3RlZCBzaG9ydGZhbGwgKEVTKQojIGZhY3RvciBjb250cmlidXRpb24gdG8gcmlzayAoRkNSKSAKCiMgTm93IHdlIHVzZSBleHBlY3RlZCBzaG9ydGZhbGwgKFZhUikgdG8gZG8gdGhlIEZDUiBkZWNvbXBvc2l0aW9uIAoKcmVwUmlzayhmaXREamlhNVlySW50U3R5bGUsIAogICAgICAgIHd0c0RqaWEsIAogICAgICAgIHJpc2sgPSAiVmFSIiwKICAgICAgICBkZWNvbXAgPSAiRlBDUiIsIAogICAgICAgIG5yb3dQcmludCA9IDEwLAogICAgICAgIHNsaWNlYnkgPSAiZmFjdG9yIiwKICAgICAgICBpc1ByaW50ID0gRiwgCiAgICAgICAgaXNQbG90ID0gVCwKICAgICAgICBsYXlvdXQgPSBjKDUsIDEpLAogICAgICAgIHN0cmlwVGV4dC5jZXggPSAwLjgsIAogICAgICAgIGF4aXMuY2V4ID0gMC44KSAKCiMgSW50ZXJwcmV0YXRpb246IAoKYGBgIAogCmBgYHtyfSAKCiMgY29tcGFyZSB0aGUgZmFjdG9yIHJpc2sgZGVjb21wb3NpdGlvbnMgb2YgYSBwb3J0Zm9saW8gdXNpbmcgYWxsIHRocmVlIHJpc2sgbWVhc3VyZXMsIHNraXBwaW5nIHRoZSByaXNrIGRlY29tcG9zaXRpb24gb2YgdGhlIGFzc2V0cyAKcmVwUmlzayhmaXREamlhNVlySW50U3R5bGUsIAogICAgICAgIHd0c0RqaWEsIAogICAgICAgIHJpc2sgPSBjKCJTZCIsICJFUyIsICJWYVIiKSwKICAgICAgICBkZWNvbXAgPSAiRlBDUiIsCiAgICAgICAgc2xpY2VieSA9ICJmYWN0b3IiLCAKICAgICAgICBpc1ByaW50ID0gVCwKICAgICAgICBpc1Bsb3QgPSBUUlVFLAogICAgICAgIGxheW91dCA9IGMoNSwgMSksCiAgICAgICAgcG9ydGZvbGlvLm9ubHkgPSBULCAKICAgICAgICBzdHJpcFRleHQuY2V4ID0gMC44LAogICAgICAgIGF4aXMuY2V4ID0gMC44KSAKCiMgSW50ZXJwcmV0YXRpb246IAoKYGBgIAogCiMjIyAzLiBGYWN0b3IgTW9kZWwgTW9udGUgQ2FybG8gClRoZSB1c2Ugb2YgZmFjdG9yIG1vZGVsIE1vbnRlIENhcmxvIChGTU1DKSBmb3IgYSBmdW5kYW1lbnRhbCBmYWN0b3IgbW9kZWwgcmVzdWx0cyBpbiBhIHNpbXVsYXRlZCBzZXQgb2YgYXNzZXQgcmV0dXJucyBiYXNlZCBvbiBhIHJlc2FtcGxpbmcgb2YgZmFjdG9yIHJldHVybnMgYW5kIGEgcmVzYW1wbGluZyBvciBzaW11bGF0aW9uIG9mIHJlc2lkdWFsIHJldHVybnMgb2YgdGhlIGZpdHRlZCBtb2RlbCwgdXNpbmcgdGhlIGV4cG9zdXJlcyBtYXRyaXggZnJvbSB0aGUgbGFzdCB0aW1lIHBlcmlvZCB1c2VkIGluIGZpdHRpbmcgdGhlIG1vZGVsLiAgClRoZSBmYWN0b3JBbmFseXRpY3MgZnVuY3Rpb24gZm1tY1NlbWlQYXJhbWV0cmljIGltcGxlbWVudHMgdGhlIGFib3ZlIEZNTUMgbWV0aG9kIGJhc2VkIG9uIGZ1bmN0aW9uIGFyYWd1bWVudHMgdGhhdCBhcmUgdGhlIHJlc3VsdCBvZiBmaXJzdCBmaXR0aW5nICBmdW5kYW1lbnRhbCBmYWN0b3IgbW9kZWwgdG8gdGhlIGRhdGEgd2l0aCBmaXRGZm0sIGNvbWJpbmVkIHdpdGggZnVuY3Rpb24gYXJndW1lbnRzIGJhc2VkIG9uIHVzZXIgb3B0aW9ucyBjb25jZXJuaW5nIHRoZSB0eXBlIG9mIEZNTUMuIFdlIHdpbGwgaWxsdXN0cmF0ZSB0aGUgdXNlIG9mIGZtbWNTZW1pUGFyYW1ldHJpYyBvbiB0aGUgREpJQSBmaXZlLXllYXIgbW9udGhseSBkYXRhIHNldCBmYWN0b3JEYXRhU2V0RGppYTVZcnMuIAoKIApgYGB7cn0gCgojIEJ1dCBmaXJzdCB3ZSB0YWtlIGEgbG9vayBhdCB0aGUgYXJndW1lbnRzIG9mIHRoZSBmdW5jdGlvbiAKYXJncyhmbW1jU2VtaVBhcmFtKSAKCmBgYCAKQWd1bWVudHM6Ci0gQiBpcyB0aGUgbnVtYmVyIG9mIGJvb3RzdHJhcCBzYW1wbGVzLgotIGZhY3Rvci5yZXQgaXMgdGhlIHNldCBvZiBmYWN0b3IgcmV0dXJucyBlc3RpbWF0ZXMgcmV0dXJuZWQgYnkgdGhlIHVzZSBvZiBmaXRGZm0KLSBiZXRhIGlzIGV4cG9zdXJlcyBtYXRyaXggZm9yIHRoZSBmaW5hbCBwZXJpb2QgcmV0dXJuZWQgYnkgZml0RmZtCi0gYWxwaGEgaXMgYSBmaXhlZCB2ZWN0b3Igb2YgaW50ZXJjZXB0IHZhbHVlcyB0aGF0IGlmIG9tbWl0ZWQgYXJlIGFzc3VtZWQgdG8gYmUgemVyby4gCgpPdXIgZXhhbXBsZSBiZWxvdyB1c2VzIHRoZSBkZWZhdWx0IHZhbHVlcyBCID0gMTAwMCwgYm9vdC5tZXRob2QgPSDigJxyYW5kb23igJ0gKG1lYW5zIHNpbXBsZSBib290c3RyYXApLCBzZWVkID0gMTIzIChmb3IgcmVwcm9kdWNpYmlsaXR5IG9mIHRoZSBleGFtcGxlKS4gIAoKV2UgdXNlIHR3byBjaG9pY2VzIG9mIHJlc2lkLmRpc3QsIGZpcnN0IHdlIHVzZSByZXNpZC5kaXN0ID0g4oCcZW1waXJpY2Fs4oCdIHdoaWNoIGNvcnJlc3BvbmRzIHRvIDItKGEpIGFib3ZlIGFuZCB0aGVuIHdlIHVzZSByZXNpZC5kaXN0ID0g4oCcbm9ybWFs4oCdLiBUaGUgdXNlciBtdXN0IHByb3ZpZGUgYXBwcm9wcmlhdGUgdmFsdWVzIGZvciByZXNpZC5wYXIgdGhhdCBkZXBlbmQgb24gdGhlIHRoZSBjaG9pY2UgZm9yIHJlc2lkLmRpc3QuIEZvciB0aGUgY2hvaWNlIHJlc2lkLmRpc3QgPSDigJxlbXBpcmljYWzigJ0gdGhlIHJlc2lkLnBhciBtdXN0IGJlIHRoZSBOIMOXIFQgZGltZW5zaW9uYWwgeHRzIHRpbWUgc2VyaWVzIGluIHRoZSAkcmVzaWR1YWxzIGNvbXBvbmVudCBvZiB0aGUgbW9kZWwgZml0LCBhbmQgZm9yIHRoZSBjaG9pY2UgcmVzaWQuZGlzdCA9IOKAnG5vcm1hbOKAnSB0aGUgcmVzaWQucGFyIG11c3QgYmUgYW4gTiDDlyAyIG1hdHJpeCB3aXRoIHRoZSBmaXJzdCBjb2x1bW4gYmVpbmcgZXN0aW1hdGVzIG9mIHRoZSBtZWFucyBvZiB0aGUgcmVzaWR1YWxzIGZvciBlYWNoIG9mIHRoZSBOIGFzc2V0cyBhbmQgdGhlIHNlY29uZCBjb2x1bW4gYmVpbmcgZXN0aW1hdGVzIG9mIHRoZSBzdGFuZGFyZCBkZXZpYXRpb25zIG9mIHRoZSByZXNpZHVhbHMgZm9yIGVhY2ggb2YgdGhlIGFzc2V0cyAKIApgYGB7cn0gCiMgSW4gb3JkZXIgdG8gdXNlIGZtbWNTZW1pUGFyYW0gZm9yIHRoZSBESklBIGRhdGEgd2UgZmlyc3QgZml0IGEgZnVuZGFtZW50YWwgZmFjdG9yIG1vZGVsICh3aXRob3V0IGFscGhhIG9yIG1hcmtldCB0ZXJtKSB0byB0aGUgZmFjdG9yRGF0YVNldERqaWE1WXJzIGRhdGEgCmRhdGEoImZhY3RvckRhdGFTZXREamlhNVlycyIpIApOID0gMzAgCgpleHBvc3VyZS52YXJzIDwtIGMoIlAyQiIsICJNS1RDQVAiLCAiU0VDVE9SIikgCgpmaXQuZmZtID0gZml0RmZtKGRhdGEgPSBmYWN0b3JEYXRhU2V0RGppYTVZcnMsCiAgICAgICAgICAgICAgICAgYXNzZXQudmFyID0gIlRJQ0tFUiIsIAogICAgICAgICAgICAgICAgIHJldC52YXIgPSAiUkVUVVJOIiwKICAgICAgICAgICAgICAgICBkYXRlLnZhciA9ICJEQVRFIiwKICAgICAgICAgICAgICAgICBleHBvc3VyZS52YXJzID0gZXhwb3N1cmUudmFycykgCmBgYCAKIApgYGB7cn0gCgojIE5leHQgd2UgdXNlIGZtbWNTZW1pUGFyYW0gdG8gY3JlYXRlIHNpbXVsYXRlZCB2YWx1ZXMgb2YgdGhlIGFzc2V0IHJldHVybnMgYmFzZWQgb24gdGhlIHVzZSBvZiBib290c3RyYXBwZWQgZmFjdG9yIHJldHVybnMgYW5kIGJvb3RzdHJhcHBlZCAoZW1waXJpY2FsKSByZXNpZHVhbHM6IApyZXNpZC5wYXIgPSBmaXQuZmZtJHJlc2lkdWFscyAKCmZtbWNEYXQgPSBmbW1jU2VtaVBhcmFtKEIgPSAxMDAwLAogICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3IucmV0ID0gZml0LmZmbSRmYWN0b3IucmV0dXJucywgCiAgICAgICAgICAgICAgICAgICAgICAgIGJldGEgPSBmaXQuZmZtJGJldGEsIAogICAgICAgICAgICAgICAgICAgICAgICByZXNpZC5wYXIgPSByZXNpZC5wYXIsCiAgICAgICAgICAgICAgICAgICAgICAgIGJvb3QubWV0aG9kID0gInJhbmRvbSIsIAogICAgICAgICAgICAgICAgICAgICAgICByZXNpZC5kaXN0ID0gImVtcGlyaWNhbCIpIApuYW1lcyhmbW1jRGF0KSAKYGBgIAoic2ltLmZ1bmQucmV0IiA9IGEgQiDDlyBOIG1hdHJpeCBvZiBzaW11bGF0ZWQgYXNzZXQgcmV0dXJucywgImJvb3QuZmFjdG9yLnJldCIgPSBhIEIgw5cgSyBtYXRyaXggb2Ygc2ltdWxhdGVkIGZhY3RvciByZXR1cm5zLCAic2ltLnJlc2lkIiA9IGEgQiDDlyBOIG1hdHJpeCBvZiBzaW11bGF0ZWQgcmVzaWR1YWxzIAogCmBgYHtyfSAKCiMgTm93IGxldOKAmXMgdmVyaWZ5IHRoYXQgdGhlIHRoYXQgcmV0dXJucyBvZiB0aGUgMzAgREpJQSBzdG9ja3Mgb3ZlciB0aGUgZml2ZS15ZWFyIHBlcmlvZCBhcmUgd2VsbCByZXByZXNlbnRlZCBieSB0aGUgc2V0IG9mIDUwMCBzaW11bGF0ZWQgc2V0cyBvZiAzMCByZXR1cm5zIGluIGZtbWNEYXQkc2ltLmZ1bmQucmV0dXJuIHdpdGggcmVzcGVjdCB0byByZXR1cm5zIG1lYW5zIGFuZCBzdGFuZGFyZCBkZXZpYXRpb25zLiBJbiBvcmRlciB0byBkbyB0aGlzIHdlIGZpcnN0IGV4dHJhY3QgdGhlIG11bHRpdmFyaWF0ZSB0aW1lIHNlcmllcyBvZiByZXR1cm5zIG9mIHRob3NlIHN0b2NrcyBmcm9tIHRoZSBkYXRhIGZyYW1lIGZhY3RvckRhdGFTZXREamlhNVlycyAKZGF0YSA9IGZhY3RvckRhdGFTZXREamlhNVlycyAKCmRqaWFEYXQgPSB0YXBwbHkoZGF0YSRSRVRVUk4sCiAgICAgICAgICAgICAgICAgbGlzdChkYXRhJERBVEUsIGRhdGEkVElDS0VSKSwKICAgICAgICAgICAgICAgICBJKSAKCmRqaWFSZXQgPSB4dHMoZGppYURhdCwKICAgICAgICAgICAgICBhcy55ZWFybW9uKHJvd25hbWVzKGRqaWFEYXQpKSkgCgpgYGAgCiAKYGBge3J9IAoKIyBOb3cgd2UgY29tcGFyZSB0aGUgc2ltdWxhdGVkIHJldHVybnMgbWVhbnMgd2l0aCB0aGUgb2JzZXJ2ZWQgcmV0dXJucyBtZWFucyBmb3IgdGhlIGZpcnN0IDEwIERKSUEgc3RvY2tzIApyb3VuZChhcHBseShkamlhUmV0LCAyLCBtZWFuKVsxOjEwXSwgMykgCgpyb3VuZChhcHBseShmbW1jRGF0JHNpbS5mdW5kLnJldCwgMiwgbWVhbilbMToxMF0sIDMpIAoKYGBgIAogCmBgYHtyfSAKCiNzYW1lIHRoaW5nIGZvciByZXR1cm5zIHN0YW5kYXJkIGRldmlhdGlvbnMgCnJvdW5kKGFwcGx5KGRqaWFSZXQsIDIsIHNkKVsxOjEwXSwgMykgCnJvdW5kKGFwcGx5KGZtbWNEYXQkc2ltLmZ1bmQucmV0LCAyLCBzZClbMToxMF0sIDMpIAoKYGBgIAogClRoZSB1c2Ugb2YgKmZtbWNTZW1pUGFyYW0qIHdpdGggYm9vdHN0cmFwcGVkIHJlc2lkdWFscyBhcyB3ZWxsIGFzIGJvb3RzdHJhcHBlZCBmYWN0b3IgcmV0dXJucyBpcyBhdHRyYWN0aXZlIGJlY2F1c2UgaXQgaXMgc2ltcGxlIGFuZCBiZWNhdXNlIGluIGFkZGl0aW9uIHRvIG1ha2luZyBubyBkaXN0cmlidXRpb25hbCBhc3N1bXB0aW9ucyBhYm91dCB0aGUgZmFjdG9yIHJldHVybnMgaXQgbWFrZXMgbm8gYXNzdW1wdGlvbnMgYWJvdXQgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIHJlc2lkdWFscy4gCiAKQnkgd2F5IG9mIGNvbnRyYXN0IGxldOKAmXMgc2VlIHdoYXQgaGFwcGVucyBpZiB3ZSBhc3N1bWUgdGhlIHJlc2lkdWFscyBhc3NvY2lhdGVkIHdpdGggdGhlIDMwIERKSUEgZml0dGVkIGZ1bmRhbWVudGFsIGZhY3RvciBtb2RlbCByZXR1cm5zIGhhdmUgbm9ybWFsIGRpc3RyaWJ1dGlvbnMgYW5kIGZpdCB0aGVtIHVzaW5nIHRoZSBzYW1wbGUgbWVhbnMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbnMgb2YgdGhlIHJlc2lkdWFscy4gIAogCiAKYGBge3J9IAoKIyBGaXJzdCB3ZSB1c2UgZm1tY1NlbWlQYXJhbSB3aXRoIGRlZmF1bHQgY2hvaWNlIHJlc2lkLmRpc3QgPSDigJxub3JtYWzigJ0gYW5kIHdpdGggcmVzaWQucGFyIGEgbWF0cml4IHdpdGggZmlyc3QgY29sdW1uIHRoZSBzYW1wbGUgbWVhbiBvZiB0aGUgcmVzaWR1YWxzIGFuZCBzZWNvbmQgY29sdW1uIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGVoIHJlc2lkdWFscyAKIApyZXNpZC5tZWFuID0gYXBwbHkoQiA9IDEwMDAsCiAgICAgICAgICAgICAgICAgICBjb3JlZGF0YShmaXQuZmZtJHJlc2lkdWFscyksCiAgICAgICAgICAgICAgICAgICAyLCAKICAgICAgICAgICAgICAgICAgIG1lYW4sCiAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFQpIAoKcmVzaWQuc2QgPSBtYXRyaXgoc3FydChmaXQuZmZtJHJlc2lkLnZhcikpIAogCnJlc2lkLnBhciA9IGNiaW5kKHJlc2lkLm1lYW4sIHJlc2lkLnNkKSAKCmZtbWNEYXROb3JtYWwgPSBmbW1jU2VtaVBhcmFtKGZhY3Rvci5yZXQgPSBmaXQuZmZtJGZhY3Rvci5yZXR1cm5zLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZXRhID0gZml0LmZmbSRiZXRhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNpZC5wYXIgPSByZXNpZC5wYXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9vdC5tZXRob2QgPSAicmFuZG9tIikgCmBgYCAKIApgYGB7cn0gCgojVGhlbiB3ZSBjb21wYXJlIHRoZSBtZWFucyBvZiB0aGUgc2ltdWxhdGVkIGFzc2V0IHJldHVybnMgd2l0aCB0aG9zZSBvZiB0aGUgYWN0dWFsIHJldHVybnMgCnJvdW5kKGFwcGx5KGRqaWFSZXQsIDIsIG1lYW4pWzE6MTBdLCAzKSAKcm91bmQoYXBwbHkoZm1tY0RhdE5vcm1hbCRzaW0uZnVuZC5yZXQsIDIsIG1lYW4pWzE6MTBdLCAzKSAKCmBgYCAKIApgYGB7cn0gCgojU2FtZSB3aXRoIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gCnJvdW5kKGFwcGx5KGRqaWFSZXQsIDIsIHNkKVsxOjEwXSwgMykgCnJvdW5kKGFwcGx5KGZtbWNEYXROb3JtYWwkc2ltLmZ1bmQucmV0LCAyLCBzZClbMToxMF0sIDMpCgpgYGAgCiAKT25jZSBhZ2FpbiB0aGUgbWVhbiB2YWx1ZXMgYWdyZWUgcXVpdGUgd2VsbCwgYnV0IHdlIHNlZSB0aGF0IHRoZSBzaW11bGF0ZWQgcmV0dXJucyBiYXNlZCBvbiB0aGUgYXNzdW1wdGlvbiBvZiBub3JtYWxseSBkaXN0cmlidXRlZCByZXR1cm5zIGhhdmUgdm9sYXRpbGl0aWVzIHRoYXQgdW5kZXItZXN0aW1hdGUgdGhlIGFjdHVhbCByZXR1cm5zIHZvbGF0aWxpdGllcyBmb3IgZWlnaHQgb2YgdGhlIGZpcnN0IDEwIHN0b2Nrcy4gSG93ZXZlciwgY29tcGFyaXNvbiBvZiB0aGUgdm9sYXRpbGl0aWVzIGZvciBhbGwgMzAgc3RvY2tzIHJldmVhbHMgdGhhdCB0aGVyZSBhcmUgb25seSAxMyBzdG9ja3MgZm9yIHdoaWNoIHRoZSB2b2xhdGlsaXRlcyBmb3IgdGhlIHNpbXVsYXRlZCByZXR1cm5zIGFyZSBzbWFsbGVyIHRoYW4gdGhvc2Ugb2YgdGhlIGFjdHVhbCByZXR1cm5zLCBhbmQgdGhhdCB3aGVuIHRoZSB2b2xhdGlsaXRpZXMgb2YgdGhlIHNpbXVsYXRlZCByZXR1cm5zIGFyZSBsYXJnZXIgdGhhbiB0aG9zZSBvZiB0aGUgYWN0dWFsIHJldHVybnMgdGhleSBhcmUgbXVjaCBsYXJnZXIsIGZvciBleGFtcGxlIC4wOTMgdmVyc3VzIC4wNjUgZm9yIENBVCBhbmQgLjEzMiB2ZXJzdSAuMDY4IGZvciBIRCAKIApNYWluIG1lc3NhZ2U6IEl0IGlzIG5vdCBzYWZlIHRvIHVzZSBub3JtYWwgZGlzdHJpYnV0aW9ucyBpbiBtb2RlbGluZyBzdG9jayByZXR1cm5zIHdpdGggYSBmdW5kYW1lbnRhbCBmYWN0b3IgbW9kZWwgKG9yIG90aGVyd2lzZSkuIEl0IGlzIGZvciB0aGlzIHJlYXNvbiB0aGF0IGZtbWNTZW1pUGFyYW0gYWxsb3dzIHlvdSB0byB1c2Ugc2tld2VkIHQtZGlzdHJpYnV0aW9ucyBhbmQgQ29ybmlzaC1GaXNoZXIgcXVhbnRpbGUgcmVycHJlc2VudGF0aW9uIG9mIG5vbi1ub3JtYWwgZGlzdHJpYnV0aW9ucyBmb3IgdGhlIHJlc2lkdWFscy4gCiAKIAojIyMgNC4gTWFya2V0IHBsdXMgSW5kdXN0cnkgcGx1cyBDb3VudHJ5IE1vZGVsIAogCkluIHRoaXMgZGlzY3Vzc2lvbiB3ZSB0cmVhdCB0aGUgdGVybXMg4oCcSW5kdXN0cnnigJ0gYW5kIOKAnFNlY3RvcuKAnSBpbnRlcmNoYW5nZWFibHksIG5vdGluZyB0aGF0IGZvciBzb21lIG1vZGVscywgZS5nLiwgYSBVLlMuIGVxdWl0eSBtb2RlbCwgb25lIG1heSBwcmVmZXIgdG8ganVzdCB1c2Ugc2VjdG9yIGZhY3RvcnMgYnV0IG1heSBhbHNvIHdpc2ggdG8gdXNlIGluZHVzdHJ5IGZhY3RvcnMsIGFuZCBhIGdsb2JhbCBtb2RlbCB3aXRoIGNvdW50cmllcyBtYXkgYWxzbyBjb250YWluIGluZHVzdHJ5IGZhY3RvcnMuIE91ciBjdXJyZW50IGV4YW1wbGVzIHVzZSBzZWN0b3IgZmFjdG9ycyBidXQgd2UgcmVmZXIgdG8gdGhlbSBpbiBvdXIgbWF0aGVtYXRpY2FsIG1vZGVscyBsb29zZWx5IGFzIGluZHVzdHJ5IGZhY3RvcnMuIAogCiAKV2Ugd2lsbCBpbGx1c3RyYXRlIHVzZSBvZiBmaXRGZm0gdG8gZml0IGEgbWFya2V0IHBsdXMgc2VjdG9yIG1vZGVsIHRvIHRoZSBESklBIHN0b2NrIHJldHVybnMgYW5kIHNlY3RvciBkYXRhLiBCdXQgZmlyc3Qgd2UgZml0IGEgcHVyZSBzZWN0b3IgbW9kZWwgd2l0aG91dCBhIG1hcmtldCBjb21wb25lbnQgYW5kIGV4YW1pbmUgdGhlIGZhY3RvciByZXR1cm4gY29lZmZpY2llbnRzIGZvciB0aGUgZmlyc3QgbW9udGggb2YgdGhlIGZpdmUteWVhciBmaXR0aW5nIHdpbmRvdyBhcyBhIHJlZmVyZW5jZSBwb2ludC4gCiAKYGBge3J9IAoKZGF0ID0gZmFjdG9yRGF0YVNldERqaWE1WXJzIApmaXRTZWMgPSBmaXRGZm0oZGF0LAogICAgICAgICAgICAgICAgYXNzZXQudmFyID0gIlRJQ0tFUiIsCiAgICAgICAgICAgICAgICByZXQudmFyID0gIlJFVFVSTiIsIAogICAgICAgICAgICAgICAgZGF0ZS52YXIgPSAiREFURSIsCiAgICAgICAgICAgICAgICBleHBvc3VyZS52YXJzID0gIlNFQ1RPUiIpIAoKYGBgIAoKYGBge3J9IAoKcm91bmQoY29lZihzdW1tYXJ5KGZpdFNlYykkc3VtLmxpc3RbWzFdXSlbLCAxXSwgMykgCnJvdW5kKGZpdFNlYyRmYWN0b3IucmV0dXJuc1sxLCBdLCAzKSAKCmBgYCAKIApOb3RlIHRoYXQgdGhlIGxhc3QgdHdvIGxpbmVzIG9mIGNvZGUgcHJvZHVjZSBpZGVudGljYWwgcmVzdWx0cy4gVGhpcyBpcyBiZWNhdXNlIHdpdGhvdXQgYW55IGNvbnN0cmFpbnRzIHN1Y2ggYXMgdGhvc2UgZGlzY3Vzc2VkIGFib3ZlLCB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBjcm9zcy1zZWN0aW9uIHJlZ3Jlc3Npb24gYXQgZWFjaCB0aW1lIHBlcmlvZCBhcmUgZXh0cmFjdGVkIHRvIGZvcm0gdGhlIHRpbWUgc2VyaWVzIG9mIGZhY3RvciByZXR1cm5zIGluIHRoZSBmYWN0b3IucmV0dXJucyBjb21wb25lbnQgb2YgdGhlIGZmbSBvYmplY3QuIE5vdyB3ZSBmaXQgYSBtYXJrZXQgcGx1cyBzZWN0b3IgbW9kZWwgYnkgYWRkaW5nIHRoZSBmaXRGIGFyZ3VtZW50IGFkZEludGVyY2VwdCA9IFQsYW5kIGV4YW1pbmUgdGhlIGNvZWZmaWNpZW50cyBny4ZtaSwxIGFuZCB0aGUgcmVzdWx0aW5nIGZhY3RvciByZXR1cm5zIMuGZm1pLDEgZm9yIHRoZSBmaXJzdCBtb250aCBvZiB0aGUgZml2ZXllYXIgZml0dGluZyB3aW5kb3cuIAogCmBgYHtyfSAKCmZpdFNlY0ludCA9IGZpdEZmbShkYXQsCiAgICAgICAgICAgICAgICAgICBhc3NldC52YXIgPSAiVElDS0VSIiwKICAgICAgICAgICAgICAgICAgIHJldC52YXIgPSAiUkVUVVJOIiwgCiAgICAgICAgICAgICAgICAgICBkYXRlLnZhciA9ICJEQVRFIiwKICAgICAgICAgICAgICAgICAgIGV4cG9zdXJlLnZhcnMgPSAiU0VDVE9SIiwKICAgICAgICAgICAgICAgICAgIGFkZEludGVyY2VwdCA9IFQpIAoKcm91bmQoY29lZihzdW1tYXJ5KGZpdFNlY0ludCkkc3VtLmxpc3RbWzFdXSlbLCAxXSwgMikgCiNleGNhY3RseSB0aGUgc2FtZSBhcyBiZWZvcmUsIGJ1dCB3ZSBhZGQgaW50ZXJjZXB0IHQ7IHRoZXJlZm9yZSB3ZSBhZGQgdGhlIG1hcmtldCBjb21wb25lbnQKYGBgIAoKYGBge3J9IAoKcm91bmQoZml0U2VjSW50JGZhY3Rvci5yZXR1cm5zWzEsIF0sIDIpIAoKYGBgIAogCmBgYHtyfSAKCnJvdW5kKHN1bShmaXRTZWNJbnQkZmFjdG9yLnJldHVybnNbMSwgLTFdKSwgMikgCiMgU3VtbWVkIHJldHVybnMgb2YgYWxsIHNlY3RvciBzaG91bGQgZXF1YWwgdG8gemVybywgZHVlIHRvIHRoZSByZWxhdGlvbnNoaXAgb2YgdGhlIHNlY3RvcnMKYGBgIAogCk5vdGUgdGhhdCB0aGUgbmV4dCB0byBsYXN0IGxpbmUgb2YgY29kZSBhYm92ZSBwcmludHMgdGhlIHVuaXF1ZSBsZWFzdCBzcXVhcmVzIG1vZGVsIGNvZWZmaWNpZW50cyB2ZWN0b3IgZ8uGbWksMSBmb3IgbW9udGggMSAoOSBvZiB0aGVtIHNpbmNlIHRoZXJlIGFyZSA5IHNlY3RvcnMpIAogCiAKIyMjIDUuIEEgU2ltdWx0YXRlZCBEYXRhIEV4YW1wbGUgCiAKV2UgaGF2ZSBjcmVhdGVkIGFuIGFydGlmaWNpYWwgZXhhbXBsZSBvZiBhIG1hcmtldCtzZWN0b3IrY291bnRyeSBtb2RlbCAod2hlcmUgc2VjdG9yIHBsYXlzIHRoZSByb2xlIG9mIGluZHVzdHJ5KSBjb25zaXN0aW5nIG9mIHJhbmRvbSByZXR1cm5zIG9mIDMwIHN0b2NrcyB3aXRoIHRocmVlIHNlY3RvcnMgZm9yIHRoZSBzZWN0b3IgZmFjdG9yIGFuZCB0d28gY291bnRyaWVzIGZvciB0aGUgY291bnRyaWVzIGZhY3RvciwgZm9yIGVhY2ggb2YgZml2ZSBtb250aHMuIFRoZSBub3JtYWxseSBkaXN0cmlidXRlZCByZXR1cm5zIGZvciB0aGUgdGhyZWUgc2VjdG9ycyBhbG9uZSBoYXZlIG1lYW5zIG9mIDEsIDIsIDMsIHdpdGggc3RhbmRhcmQgZGV2aWF0aW9ucyAuMi4gVGhlIHR3byBjb3VudHJpZXMgY29udHJpYnV0ZSBhZGRpdGlvbmFsIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHJldHVybnMgaGF2aW5nIG1lYW5zIDQgYW5kIDUgd2l0aCBzdGFuZGFyZCBkZXZpYXRpb25zIC4yLiBTbyByZXR1cm5zIGFzc29jaWF0ZWQgd2l0aCB0aGUgZmlyc3QgY291bnRyeSBoYXZlIG1lYW5zIDUsIDYsIDcgYW5kIG1lYW5zIGFzc29jaWF0ZWQgd2l0aCB0aGUgc2Vjb25kIApjb3VudHJ5IGhhdmUgbWVhbnMgNiwgNywgOC4gVGh1cyB0aGUgb3ZlcmFsbCBtZWFuIG9mIDYuNS4gVGhlIGNvZGUgZm9yIGNyZWF0aW5nIHRoZSByZXR1cm5zIGlzIGFzIGZvbGxvd3M6IAogCmBgYHtyfSAKCiMgQ291bnRyeSBJbmNyZW1lbnRhbCBDb21wb25lbnRzIG9mIEFzc2V0IFJldHVybnMgCnNldC5zZWVkKDEwMDAwKQoKQmluZCA9IGNiaW5kKHJlcCgxLCAzMCksIAogICAgICAgICAgICAgYyhyZXAoMSwgMTApLCByZXAoMCwgMjApKSwgCiAgICAgICAgICAgICBjKHJlcCgwLCAxMCksIHJlcCgxLCAxMCksIHJlcCgwLCAxMCkpLCAKICAgICAgICAgICAgIGMocmVwKDAsIDIwKSwgcmVwKDEsIDEwKSkpIAoKY3R5MSA9IG1hdHJpeChyZXAoYygwLCAxKSwgMTUpKSAKCmN0eTIgPSBtYXRyaXgocmVwKGMoMSwgMCksIDE1KSkgCgpCbWljID0gY2JpbmQoQmluZCwgY3R5MSwgY3R5MikgCgpkaW1uYW1lcyhCbWljKVtbMl1dID0gYygibWt0IiwgInNlYzEiLCAic2VjMiIsICJzZWMzIiwgImN0eTEiLCAiY3R5MiIpIAoKci5hZGQgPSBybm9ybSgzMCwgNCwgMC4yKSAKci5jdHkxID0gcmVwKDAsIDMwKSAKci5jdHkyID0gcmVwKDAsIDMwKSAKCmZvciAoaSBpbiAxOjMwKSAKICB7CiAgaWYgKEJtaWNbaSwgImN0eTEiXSA9PSAxKSAKICAgIHsgCiAgICByLmN0eTFbaV0gPSByLmFkZFtpXSAKICAgIHIuY3R5MltpXSA9IDAgCiAgICB9IAogIGVsc2UgCiAgICB7IAogICAgICByLmN0eTFbaV0gPSAwCiAgICAgIHIuY3R5MltpXSA9IHIuYWRkW2ldICsgMQogICAgfSAKICB9IAoKCiMgQXNzZXQgUmV0dXJucyBmb3IgTWFya2V0K0luZHVzdHJ5K0NvdW50cnkgTW9kZWwgCm11ID0gYygxLCAyLCAzKSAKc2QgPSBjKDAuMiwgMC4yLCAwLjIpIApyID0gbGlzdCgpIApyLm1pYyA9IGxpc3QoKSAKZml0TWljID0gbGlzdCgpIApmaXRNaWMxID0gbGlzdCgpIAoKZm9yIChpIGluIDE6NSkgCiAgewogIHNldC5zZWVkKDEwOTk5MjMgKyAoaSAtIDEpKSAKICByW1tpXV0gPSBjKHJub3JtKDEwLCBtdVsxXSwgc2RbMV0pLCAKICAgICAgICAgICAgIHJub3JtKDEwLCBtdVsyXSwgc2RbMl0pLCAKICAgICAgICAgICAgIHJub3JtKDEwLCBtdVszXSwgc2RbM10pKSAKICByLm1pY1tbaV1dID0gcltbaV1dICsgci5jdHkxICsgci5jdHkyIAogIH0gCgpgYGAgCiAKYGBge3J9IAoKI3FxLXBsb3Qgb2YgdGhlIDMwIGFzc2V0IHJldHVybnMgZm9yIHRoZSBmaXJzdCBvZiB0aGUgNSB0aW1lIHBlcmlvZHMgCiNEaWUgQmVvYmFjaHR1bmdzd2VydGUgendlaWVyIE1lcmttYWxlLCBkZXJlbiBWZXJ0ZWlsdW5nIG1hbiB2ZXJnbGVpY2hlbiB3aWxsLCB3ZXJkZW4gamV3ZWlscyBkZXIgR3LDtsOfZSBuYWNoIGdlb3JkbmV0LiBEaWVzZSBnZW9yZG5ldGVuIERhdGVuIHdlcmRlbiB6dSBXZXJ0ZXBhYXJlbiB6dXNhbW1lbmdlZmFzc3QgdW5kIGluIGVpbmVtIEtvb3JkaW5hdGVuc3lzdGVtIGFiZ2V0cmFnZW4uIEVyZ2ViZW4gZGllIFB1bmt0ZSAoYW5uw6RoZXJuZCkgZWluZSBHZXJhZGUsIGthbm4gbWFuIHZlcm11dGVuLCBkYXNzIGRlbiBiZWlkZW4gTWVya21hbGVuIGRpZSBnbGVpY2hlIFZlcnRlaWx1bmcgenUgR3J1bmRlIGxpZWd0LiBQcm9ibGVtYXRpc2NoIGlzdCBkYXMgVmVyZmFocmVuLCB3ZW5uIHZvbiBkZW4gYmVpZGVuIE1lcmttYWxlbiB1bnRlcnNjaGllZGxpY2ggdmllbGUgQmVvYmFjaHR1bmdlbiB2b3JsaWVnZW4uIEhpZXIga2FubiBtaXQgSW50ZXJwb2xhdGlvbnN2ZXJmYWhyZW4gYWJnZWhvbGZlbiB3ZXJkZW4uCnFxbm9ybShyLm1pY1tbMV1dLAogICAgICAgbWFpbiA9ICJNSUMgTW9kZWwgRXF1aXR5IFJldHVybnMgZm9yIEZpcnN0IFBlcmlvZCIsIAogICAgICAgeGxhYiA9ICJOT1JNQUwgUVEtUExPVCIsCiAgICAgICB5bGFiID0gIlJFVFVSTlMiKSAKIApgYGAgCiAKTm93IHdlIGJ1aWxkIHRoZSBkYXRhIGZyYW1lIHJlcXVpcmVkIGJ5IGZpdEZmbSwgZml0IHRoZSBNSUMgbW9kZWwgYW5kIGRpc3BsYXkgdGhlIGZhY3RvciByZXR1cm5zIGZvciBlYWNoIG9mIHRoZSBmaXZlIG1vbnRocy4gV2hhdCB3ZSBoYXZlIGJlZW4gY2FsbGluZyB0aGUgSW5kdXN0cnkgZmFjdG9yIGlzIGNhbGxlZCBTZWN0b3IgZm9yIHRoaXMgZXhhbXBsZSAKCiAKYGBge3J9IAoKUmV0dXJucyA9IHVubGlzdChyLm1pYykgCgpDT1VOVFJZID0gcmVwKHJlcChjKCJVUyIsICJJbmRpYSIpLCAxNSksIDUpIAoKU0VDVE9SID0gcmVwKHJlcChjKCJTRUMxIiwgIlNFQzIiLCAiU0VDMyIpLCBlYWNoID0gMTApLCA1KSAKClRJQ0tFUiA9IHJlcChjKExFVFRFUlNbMToyNl0sIHBhc3RlMCgiQSIsIExFVFRFUlNbMTo0XSkpLCA1KSAKCkRBVEUgPSByZXAoc2VxKGFzLkRhdGUoIjIwMDAvMS8xIiksIGJ5ID0gIm1vbnRoIiwgbGVuZ3RoLm91dCA9IDUpLCBlYWNoID0gMzApIAoKZGF0YS5taWMgPSBkYXRhLmZyYW1lKERBVEUgPSBhcy5jaGFyYWN0ZXIoREFURSksCiAgICAgICAgICAgICAgICAgICAgICBUSUNLRVIsIAogICAgICAgICAgICAgICAgICAgICAgUmV0dXJucywgCiAgICAgICAgICAgICAgICAgICAgICBTRUNUT1IsIAogICAgICAgICAgICAgICAgICAgICAgQ09VTlRSWSkgCgpleHBvc3VyZS52YXJzID0gYygiU0VDVE9SIiwgIkNPVU5UUlkiKSAKCmZpdCA9IGZpdEZmbShkYXRhID0gZGF0YS5taWMsCiAgICAgICAgICAgICBhc3NldC52YXIgPSAiVElDS0VSIiwgCiAgICAgICAgICAgICByZXQudmFyID0gIlJldHVybnMiLAogICAgICAgICAgICAgZGF0ZS52YXIgPSAiREFURSIsCiAgICAgICAgICAgICBleHBvc3VyZS52YXJzID0gZXhwb3N1cmUudmFycywgCiAgICAgICAgICAgICBhZGRJbnRlcmNlcHQgPSBUKSAKCmZpdCRmYWN0b3IucmV0dXJucyAKCgpgYGAgCiAKV2Ugc2VlIHRoYXQgdGhlIE1hcmtldCB2YWx1ZXMgb2YgdGhlIGZhY3RvciBoYXZlIHZhbHVlcyBjbHVzdGVyaW5nIGFyb3VuZCA2LjUgYXMgZXhwZWN0ZWQuIFdlIGNhbiBhbHNvIHNlZSB0aGF0IHRoZSB0aHJlZSBzZWN0b3IgZmFjdG9yIHJldHVybnMgc3VtIHRvIHplcm8gYW5kIHRoZSB0d28gY291bnRyeSBmYWN0b3IgcmV0dXJucyBzdW0gdG8gemVybywgYXMgZXhwZWN0ZWQgZHVlIHRvIHRoZSBjb25zdHJhaW50cyB0aGF0IHRoZXkgc3VtIHRvIHplcm8u